• 2022谷粒商城学习笔记(八)规格参数相关功能


    前言

    本系列博客基于B站谷粒商城,只作为本人学习总结使用。这里我会比较注重业务逻辑的编写和相关配置的流程。有问题可以评论或者联系我互相交流。原视频地址谷粒商城雷丰阳版。本人git仓库地址Draknessssw的谷粒商城


    相关概念

    PO 数据库表记录,不包含任何数据库操作。

    DO 业务实体

    TO 不同程序之间传输数据对象

    DTO view层和Service层的数据传输对象

    DAO 数据库访问对象

    VO 业务层数据传输对象,可以和数据库表不一致,由new创建,由GC回收。接收业务请求,然后响应(一般是自定义信息)业务需要的消息。可以用来代替数据校验注解。

    BO 结合PO和VO进行业务操作


    保存商品的规格参数

    这里要对商品属性表进行操作,但是商品属性表没有商品分组属性,而前端请求头确实是有这个信息的

    在这里插入图片描述

    package com.xxxx.gulimall.product.entity;
    
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    
    import java.io.Serializable;
    import java.util.Date;
    import lombok.Data;
    
    /**
     * 商品属性
     * 
     * @author draknessssw
     * @email 2571562818@qq.com
     * @date 2022-07-02 17:11:25
     */
    @Data
    @TableName("pms_attr")
    public class AttrEntity implements Serializable {
    	private static final long serialVersionUID = 1L;
    
    	/**
    	 * 属性id
    	 */
    	@TableId
    	private Long attrId;
    	/**
    	 * 属性名
    	 */
    	private String attrName;
    	/**
    	 * 是否需要检索[0-不需要,1-需要]
    	 */
    	private Integer searchType;
    	/**
    	 * 值类型[0-为单个值,1-可以选择多个值]
    	 */
    	private Integer valueType;
    	/**
    	 * 属性图标
    	 */
    	private String icon;
    	/**
    	 * 可选值列表[用逗号分隔]
    	 */
    	private String valueSelect;
    	/**
    	 * 属性类型[0-销售属性,1-基本属性,2-既是销售属性又是基本属性]
    	 */
    	private Integer attrType;
    	/**
    	 * 启用状态[0 - 禁用,1 - 启用]
    	 */
    	private Long enable;
    	/**
    	 * 所属分类
    	 */
    	private Long catelogId;
    	/**
    	 * 快速展示【是否展示在介绍上;0-否 1-是】,在sku中仍然可以调整
    	 */
    	private Integer showDesc;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    写一个AttrVo
    在这里插入图片描述
    加入商品分组字段,去掉数据库操作特有的注解如@TableId

    package com.xxxx.gulimall.product.vo;
    
    import lombok.Data;
    
    @Data
    public class AttrVo {
    
        /**
         * 属性id
         */
        private Long attrId;
        /**
         * 属性名
         */
        private String attrName;
        /**
         * 是否需要检索[0-不需要,1-需要]
         */
        private Integer searchType;
        /**
         * 属性图标
         */
        private String icon;
        /**
         * 可选值列表[用逗号分隔]
         */
        private String valueSelect;
        /**
         * 属性类型[0-销售属性,1-基本属性,2-既是销售属性又是基本属性]
         */
        private Integer attrType;
        /**
         * 启用状态[0 - 禁用,1 - 启用]
         */
        private Long enable;
        /**
         * 所属分类
         */
        private Long catelogId;
        /**
         * 快速展示【是否展示在介绍上;0-否 1-是】,在sku中仍然可以调整
         */
        private Integer showDesc;
    
        private Long attrGroupId;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    业务逻辑

    在这里插入图片描述
    实现类

    通过BeanUtils.copyProperties(attr,attrEntity)方法将AttrVo的数据拷贝到商品属性实体表里面(Vo到Po),此时完成第一步,保存两者对应的基本数据。

     		AttrEntity attrEntity = new AttrEntity();
            BeanUtils.copyProperties(attr,attrEntity);
            //1、保存基本数据
            this.save(attrEntity);
    
    • 1
    • 2
    • 3
    • 4

    新建一个公共枚举类作用于销售属性和规格属性的标识取值

    在这里插入图片描述

    package com.xxxx.common.constant;
    
    
    public class ProductConstant {
    
        public enum AttrEnum {
            ATTR_TYPE_BASE(1,"基本属性"),
            ATTR_TYPE_SALE(0,"销售属性");
    
            private int code;
    
            private String msg;
    
            public int getCode() {
                return code;
            }
    
            public String getMsg() {
                return msg;
            }
    
            AttrEnum(int code, String msg) {
                this.code = code;
                this.msg = msg;
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    如果这时候传入的表单信息中关联关系是基本属性且不为空,传入属性&属性分组关联实体类(由它来保存属性的关联关系),设置这个实体类的属性分组id和组内排序。即提交的表单中的分组关系id和实体类的商品id。保存到数据库即可。

    最终效果如下

    @Autowired
    AttrAttrgroupRelationDao relationDao;
    
    • 1
    • 2
    @Transactional
        @Override
        public void saveAttr(AttrVo attr) {
            AttrEntity attrEntity = new AttrEntity();
            BeanUtils.copyProperties(attr,attrEntity);
            //1、保存基本数据
            this.save(attrEntity);
    
            //2、保存关联关系
            //判断类型,如果是基本属性就设置分组id
            if (attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() && attr.getAttrGroupId() != null) {
                AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
                relationEntity.setAttrGroupId(attr.getAttrGroupId());
                relationEntity.setAttrId(attrEntity.getAttrId());
                relationDao.insert(relationEntity);
            }
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    分页查询规格参数信息

    在这里插入图片描述

     @GetMapping("/{attrType}/list/{catelogId}")
        public R baseAttrList(@RequestParam Map<String, Object> params,
                              @PathVariable("catelogId") Long catelogId,
                              @PathVariable("attrType")String type){
    
            PageUtils page = attrService.queryBaseAttrPage(params,catelogId,type);
            return R.ok().put("page", page);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    实现类

    首先匹配条件先匹配分类id, 。
    如果当前商品分类id不等于0,匹配条件添加分类id。
    如果输入的字段非空,去模糊匹配商品id和商品名。
    然后通过Ipage插件返回分页匹配数据。

    QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().eq("attr_type","base".equalsIgnoreCase(type)?ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode():ProductConstant.AttrEnum.ATTR_TYPE_SALE.getCode());
    
            if (catelogId != 0) {
                queryWrapper.eq("catelog_id",catelogId);
            }
    
            String key = (String) params.get("key");
    
            if (!StringUtils.isEmpty(key)) {
                queryWrapper.and((wrapper) ->{
                    wrapper.eq("attr_id",key).or().like("attr_name",key);
                        });
            }
    
            IPage<AttrEntity> page = this.page(
                    new Query<AttrEntity>().getPage(params),
                    queryWrapper
            );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    此时虽然已经用分页接口接收数据,但是仍然需要继续封装。

    PageUtils pageUtils = new PageUtils(page);
    
    • 1

    新建商品响应数据
    在这里插入图片描述
    继承AttVo之后,只需要写自己额外的处理字段即可(分类名,组名,分类路径)

    package com.xxxx.gulimall.product.vo;
    
    import lombok.Data;
    
    
    
    @Data
    public class AttrRespVo extends AttrVo {
    
        /**
         *
         */
        private String catelogName;
    
        private String groupName;
    
        private Long[] catelogPath;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这里先用page.getRecords()将分页数据记录下来。

    List<AttrEntity> records = page.getRecords();
    
    • 1

    使用streamAPI进行重新封装,最后收集成list

    List<AttrRespVo> respVos = records.stream().map((attrEntity) -> {
    ……
    ……
    }).collect(Collectors.toList());
    
    • 1
    • 2
    • 3
    • 4

    接着将商品基本属性拷贝到attrRespVo中

    			AttrRespVo attrRespVo = new AttrRespVo();
    			BeanUtils.copyProperties(attrEntity, attrRespVo);
    
    • 1
    • 2

    设置需要返回的分组的名字
    如果……,通过商品表属性id来匹配这个商品所在的商品&商品属性表中id一样的记录。当商品&商品属性表中商品属性id和商品属性所在组的id均不为空时,通过商品&商品属性表的商品属性id查询这个商品属性id对应的组id,继而去设置分组的名字。
    简而言之,这是两个表被中间表对应的过程。

    			if ("base".equalsIgnoreCase(type)) {
                    AttrAttrgroupRelationEntity attrId =
                            relationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id",attrEntity.getAttrId()));
                    if (attrId != null && attrId.getAttrGroupId() != null) {
                        AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrId.getAttrGroupId());
                        attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName());
                    }
    
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    而分类名可以直接通过商品属性的分类id对应设置。

    			CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
                if (categoryEntity != null) {
                    attrRespVo.setCatelogName(categoryEntity.getName());
    
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    最后返回封装好的数据

    		pageUtils.setList(respVos);
            return pageUtils;
    
    • 1
    • 2

    最终如下

    	@Autowired
        AttrAttrgroupRelationDao relationDao;
        
    	@Autowired
        AttrGroupDao attrGroupDao;
    
        @Autowired
        CategoryDao categoryDao;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    @Override
        public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId, String type) {
    
            QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().eq("attr_type","base".equalsIgnoreCase(type)?ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode():ProductConstant.AttrEnum.ATTR_TYPE_SALE.getCode());
    
            if (catelogId != 0) {
                queryWrapper.eq("catelog_id",catelogId);
            }
    
            String key = (String) params.get("key");
    
            if (!StringUtils.isEmpty(key)) {
                queryWrapper.and((wrapper) ->{
                    wrapper.eq("attr_id",key).or().like("attr_name",key);
                        });
            }
    
            IPage<AttrEntity> page = this.page(
                    new Query<AttrEntity>().getPage(params),
                    queryWrapper
            );
    
            PageUtils pageUtils = new PageUtils(page);
            List<AttrEntity> records = page.getRecords();
    
            List<AttrRespVo> respVos = records.stream().map((attrEntity) -> {
                AttrRespVo attrRespVo = new AttrRespVo();
                BeanUtils.copyProperties(attrEntity, attrRespVo);
    
                //设置分类和分组的名字
                if ("base".equalsIgnoreCase(type)) {
                    AttrAttrgroupRelationEntity attrId =
                            relationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id",attrEntity.getAttrId()));
                    if (attrId != null && attrId.getAttrGroupId() != null) {
                        AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrId.getAttrGroupId());
                        attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName());
                    }
    
                }
    
                CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
                if (categoryEntity != null) {
                    attrRespVo.setCatelogName(categoryEntity.getName());
    
                }
                return attrRespVo;
            }).collect(Collectors.toList());
    
            pageUtils.setList(respVos);
            return pageUtils;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    获取单个具体的规格信息

    在这里插入图片描述

     /**
         * 信息
         */
        @RequestMapping("/info/{attrId}")
        public R info(@PathVariable("attrId") Long attrId){
    
    
            AttrRespVo respVo = attrService.getAttrInfo(attrId);
            return R.ok().put("attr", respVo);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    实现类
    根据传入商品属性id查询其详细信息

    		AttrEntity attrEntity = this.getById(attrId);
    
    • 1

    把查询到的规格属性信息拷到respVo中

    		AttrRespVo respVo = new AttrRespVo();
            BeanUtils.copyProperties(attrEntity,respVo);
    
    • 1
    • 2

    判断是否是基本数据类型。
    通过请求参数查询属性&属性分组表的记录,要是查到了记录,就往这个返回数据里设置分组信息,然后通过查到的记录的组id来查询属性分组实体类的分组名称,若是成功获取到了这个名称,返回给respVo

    		if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
                //1、设置分组信息
                AttrAttrgroupRelationEntity attrgroupRelationEntity = relationDao.selectOne
                        (new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId));
                if (attrgroupRelationEntity != null) {
                    respVo.setAttrGroupId(attrgroupRelationEntity.getAttrGroupId());
                    //获取分组名称
                    AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrgroupRelationEntity.getAttrGroupId());
                    if (attrGroupEntity != null) {
                        respVo.setGroupName(attrGroupEntity.getAttrGroupName());
                    }
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    接着设置三级分类路径和分类名称

    //2、设置分类信息
            Long catelogId = attrEntity.getCatelogId();
            Long[] catelogPath = categoryService.findCatelogPath(catelogId);
    
            respVo.setCatelogPath(catelogPath);
            CategoryEntity categoryEntity = categoryDao.selectById(catelogId);
            if (categoryEntity != null) {
                respVo.setCatelogName(categoryEntity.getName());
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    查询路径的方法

     /**
         * 根据catelogId查询所有父分类ID
         */
        @Override
        public Long[] findCatelogPath(Long catelogId) {
            List<Long> paths = new ArrayList<>();
            // 递归查询父类
            paths = findParentPath(catelogId, paths);
            // 逆序,父在前
            Collections.reverse(paths);
            return paths.toArray(new Long[paths.size()]);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    最终效果如下

    @Override
        public AttrRespVo getAttrInfo(Long attrId) {
            //查询详细信息
            AttrEntity attrEntity = this.getById(attrId);
    
            //查询分组信息
            AttrRespVo respVo = new AttrRespVo();
            BeanUtils.copyProperties(attrEntity,respVo);
    
            //判断是否是基本类型
            if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
                //1、设置分组信息
                AttrAttrgroupRelationEntity attrgroupRelationEntity = relationDao.selectOne
                        (new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId));
                if (attrgroupRelationEntity != null) {
                    respVo.setAttrGroupId(attrgroupRelationEntity.getAttrGroupId());
                    //获取分组名称
                    AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrgroupRelationEntity.getAttrGroupId());
                    if (attrGroupEntity != null) {
                        respVo.setGroupName(attrGroupEntity.getAttrGroupName());
                    }
                }
            }
    
            //2、设置分类信息
            Long catelogId = attrEntity.getCatelogId();
            Long[] catelogPath = categoryService.findCatelogPath(catelogId);
    
            respVo.setCatelogPath(catelogPath);
            CategoryEntity categoryEntity = categoryDao.selectById(catelogId);
            if (categoryEntity != null) {
                respVo.setCatelogName(categoryEntity.getName());
            }
    
            return respVo;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    规格修改

    在这里插入图片描述
    实现类

    还是差不多的操作……更新商品属性,更新属性&属性关联表的组id和属性id,统计需要更新的记录的数量,大于零就更新,如果没有记录就新增记录。

    最终效果如下

    @Transactional
        @Override
        public void updateAttr(AttrVo attr) {
            AttrEntity attrEntity = new AttrEntity();
            BeanUtils.copyProperties(attr,attrEntity);
    
            this.updateById(attrEntity);
    
            if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
                //1、修改分组关联
                AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
                relationEntity.setAttrGroupId(attr.getAttrGroupId());
                relationEntity.setAttrId(attr.getAttrId());
    
                Integer count = relationDao.selectCount(new QueryWrapper<AttrAttrgroupRelationEntity>()
                        .eq("attr_id", attr.getAttrId()));
    
                if (count > 0) {
                    relationDao.update(relationEntity,
                            new UpdateWrapper<AttrAttrgroupRelationEntity>().eq("attr_id",attr.getAttrId()));
                } else {
                    relationDao.insert(relationEntity);
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    以后还是简单点吧,今天花了太多时间了……

  • 相关阅读:
    弘辽科技:做好产品标题,让链接免费流量快速爆起来
    QT信号槽的5种连接方式Qt::ConnectionType
    渲染器——双端Diff算法
    【leetcode41-----可被5整除的二进制前缀】
    金仓数据库 KingbaseGIS 使用手册(6.4. 几何对象存取函数)
    《古诗词里的快意人生》读后感
    分词工具使用系列——sentencepiece使用
    基于Python3搭建qt开发环境
    算法补天系列之——KMP算法,即字符串匹配算法
    前端基础之《Bootstrap(6)—全局CSS样式_表单》
  • 原文地址:https://blog.csdn.net/qq_44737138/article/details/126411074