谷粒商城--SPU和SKU(属性分组、规格参数、销售属性)-2

简介: 谷粒商城--SPU和SKU(属性分组、规格参数、销售属性)

规格参数详情

接口如下:

7797f3f5e440b6e01b7bb89e1b1a3653_7b7e1e648fd3233d1cb655bd1688689b.png


什么是规格参数?


34e5c3bc390d5b8d08a4d6332e57e6a4_d49d18ad35c2fab16652e9a7e7ef05d3.png


保存规格参数

controller

/**
 * 保存
 */
@RequestMapping("/save")
public R save(@RequestBody AttrVo vo){
  attrService.saveAttr(vo);
    return R.ok();
}

service


这里注意,因为添加规格参数的时候会有选择属性组,因为属性组和属性是通过关联关系表连接的所以要有级联操作。


在往pms_attr表插入数据的时候,pms_attr_group_relation也要插入


小bug:这里有个注意点,当添加规格参数的时候如果没有指定规格参数所属分组,那么就不应该在关联表中保存关联关系!!!


@Override
public void saveAttr(AttrVo attr) {
    AttrEntity attrEntity = new AttrEntity();
    //1.将前端接收数据的对象vo赋值给attrEntity对象,从而更新数据库
    BeanUtils.copyProperties(attr, attrEntity);
    this.save(attrEntity);
    if (attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() && attr.getAttrGroupId() != null) {
        //2.保存关联关系
        //因为属性组和属性是通过关联关系表连接的
        AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
        relationEntity.setAttrGroupId(attr.getAttrGroupId());
        relationEntity.setAttrId(attrEntity.getAttrId());
        relationService.save(relationEntity);
    }
}

显示规格参数

controller


/**
 * 显示规格参数
 */
@GetMapping("/base/list/{catelogId}")
public R baseAttrList(@RequestParam Map<String, Object> params,
                      @PathVariable("catelogId") Integer catelogId) {
    PageUtils page = attrService.queryBaseAttrPage(params, catelogId);
    return R.ok().put("page", page);
}

service

//分页查询规格参数
@Override
public PageUtils queryBaseAttrPage(Map<String, Object> params, Integer catelogId) {
    QueryWrapper<AttrEntity> wrapper = new QueryWrapper<>();
    if (catelogId != 0) {
        //如果不是一级分类,那么查询的时候加上where catelog_id = ?
        wrapper.eq("catelog_id", catelogId);
    }
    //多条件模糊查询
    //搜索框里的key不但可以对catelog_id进行模糊查询,对attr_name也模糊查询
    String key = (String) params.get("key");
    if (!StringUtils.isEmpty(key)) {
        wrapper.eq("attr_id", key).or().like("attr_name", key);
    }
    //多条件分页查询
    IPage<AttrEntity> page = this.page(
        new Query<AttrEntity>().getPage(params),
        wrapper);
    PageUtils pageUtils = new PageUtils(page);
    return pageUtils;
}

测试


如下:


87d25279ab828aed49074d75f5551135_ff296593d530fd1ff3eaef526b7562ea.png


这些属性的分类和所属分组怎么查呢?


规格参数表(pms_attr)中,有所属分类的信息,可以直接调用分类的service进行查询


那分组信息怎么查询呢?规格参数表中没有所属分类相关的信息…


这里我们就要借助第三张表,属性和分组表(pms_attr_attrgroup_relation)进行查询


通过规格参数表(pms_attr)获得attr_id,之后在调用属性和分组表的service获得属性和分组表的实体类,从而获得该属性的分组


下面通过stream流的方式,通过map给list集合中的每一项做映射给新实体类(AttrRespVo)赋值,最后返回AttrRespVo


小bug:这里显示规格参数的时候,会显示规格。参数对应的分组、分类,那么如果它们查出对象分组id或分类id为空那就不设置名字if (attrId != null && attrId.getAttrGroupId() != null) {…}


//分页查询规格参数
@Override
public PageUtils queryBaseAttrPage(Map<String, Object> params, String type, Integer catelogId) {
    QueryWrapper<AttrEntity> wrapper = new QueryWrapper<AttrEntity>()
        .eq("attr_type", "base".equalsIgnoreCase(type) ? ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() : ProductConstant.AttrEnum.ATTR_TYPE_SALE.getCode());
    if (catelogId != 0) {
        //如果不是一级分类,那么查询的时候加上where catelog_id = ?
        //IgnoreCase忽略大小写
        wrapper.eq("catelog_id", catelogId);
    }
    //多条件模糊查询
    //搜索框里的key不但可以对catelog_id进行模糊查询,对attr_name也模糊查询
    String key = (String) params.get("key");
    if (!StringUtils.isEmpty(key)) {
        wrapper.eq("attr_id", key).or().like("attr_name", key);
    }
    //多条件分页查询
    IPage<AttrEntity> page = this.page(
        new Query<AttrEntity>().getPage(params),
        wrapper);
    PageUtils pageUtils = new PageUtils(page);
    List<AttrEntity> list = page.getRecords();
    //        .map()这个方法是对被筛选过后的流进行映射,一般是对属性进行赋值。
    List<AttrRespVo> resultList = list.stream().map(item -> {
        AttrRespVo attrRespvo = new AttrRespVo();
        BeanUtils.copyProperties(item, attrRespvo);
        //设置分类和分组的名字
        if ("base".equalsIgnoreCase(type)) {
            AttrAttrgroupRelationEntity attrId = relationService.
                getOne(new QueryWrapper<AttrAttrgroupRelationEntity>()
                       .eq("attr_id", item.getAttrId()));
            if (attrId != null && attrId.getAttrGroupId() != null) {
                //attrgroupRelationEntity.getAttrGroupId()也可以,这里可以直接放进去对象
                AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrId.getAttrGroupId());
                attrRespvo.setGroupName(attrGroupEntity.getAttrGroupName());
            }
        }
        CategoryEntity categoryEntity = categoryService.getById(item.getCatelogId());
        if (categoryEntity != null) {
            attrRespvo.setCatelogName(categoryEntity.getName());
        }
        //返回最后的封装结果
        return attrRespvo;
    }).collect(Collectors.toList());
    //返回的结果是一个集合
    pageUtils.setList(resultList);
    //        返回分页后的集合对象
    return pageUtils;
}

AttrRespVo


@Data
public class AttrRespVo extends AttrVo {
    private String catelogName;
    private String  groupName;
}

测试


06be5ea8dc115b32c5b06d131f876ecc_a2a6b7da6c0afa6d9c06d8f6bdbdd537.png


规格参数回显

可以看出所属分类和分组都是由这条请求查询的,那么我们改这个接口功能就行


相当于在原来查询基础上返回分类路径信息,分组信息


c1987704e4055866eee50a78cb5bf23c_a8ae8980e4f6322397de7a54251b18ab.png


controller

/**
 * 信息
 */
@RequestMapping("/info/{attrId}")
public R info(@PathVariable("attrId") Long attrId) {
    AttrRespVo respVo = attrService.getAttrInfo(attrId);
    return R.ok().put("attr", respVo);
}

service


@Override
public AttrRespVo getAttrInfo(Long attrId) {
    AttrRespVo respVo = new AttrRespVo();
    AttrEntity attrEntity = this.getById(attrId);
    BeanUtils.copyProperties(attrEntity, respVo);
    /**
     * 设置分组信息
     */
    AttrAttrgroupRelationEntity attrgroupRelationEntity = relationService.
            getOne(new QueryWrapper<AttrAttrgroupRelationEntity>()
                    .eq("attr_id", attrEntity.getAttrId()));
    if (attrgroupRelationEntity != null){
        respVo.setAttrGroupId(attrgroupRelationEntity.getAttrGroupId());
        Long attrGroupId = attrgroupRelationEntity.getAttrGroupId();
        AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrGroupId);
        if (attrGroupEntity != null) {
            respVo.setGroupName(attrGroupEntity.getAttrGroupName());
        }
    }
    /**
     * 设置分类信息
     */
    Long catelogId = attrEntity.getCatelogId();
    //有了分类的完整路径,接下来就设置分类名字
    Long[] catelogPath = categoryService.findCatelogPath(catelogId);
    respVo.setCatelogPath(catelogPath);
    //获得分类名字
    CategoryEntity categoryEntity = categoryService.getById(catelogId);
    if (categoryEntity != null) {
        respVo.setCatelogName(categoryEntity.getName());
    }
    return respVo;
}

测试


205ec1e44942181bf2e92c20ff80ae19_389a62f9bac93bd2fb14d5d40f0cd3e2.png


修改Or增加

提交修改分类和分组是无效的?


更改用的还是默认的update方法,所以我们改update接口!


8b4ff92e94cd600ebf3cc7eb9bce9df6_9771230c7e7475cd81566bb7bb82e702.png


controller


/**
 * 修改
 */
@RequestMapping("/update")
public R update(@RequestBody AttrVo attr) {
    attrService.updateAttr(attr);
    return R.ok();
}

service


这里做了优化,对于规格参数中没有所属分组的,如果指定了不在是修改而是添加!


怎么判断规格参数有没有所属分组呢?


拿attr_id去pms_attr_attrgroup_relation表中查询,如果改attr_id存在与该表,那就修改关联关系


如果没有数据,那么就在此表添加数据!

@Transactional
@Override
public void updateAttr(AttrVo attr) {
    AttrEntity attrEntity = new AttrEntity();
    BeanUtils.copyProperties(attr, attrEntity);
    this.updateById(attrEntity);
    //修改分组关联
    AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
    attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
    attrAttrgroupRelationEntity.setAttrId(attr.getAttrId());
    //统计attr_id的关联属性,如果没有初始分组,则进行添加操作;有则进行修改操作
    Integer count = relation.selectCount(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId()));
    if (count > 0) {
        relation.update(attrAttrgroupRelationEntity, new UpdateWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId()));
    } else {
        relation.insert(attrAttrgroupRelationEntity);
    }
}

spu规格维护

出现400页面,在数据库添加


INSERT INTO sys_menu (menu_id, parent_id, name, url, perms, type, icon, order_num) VALUES (76, 37, '规格维护', 'product/attrupdate', '', 2, 'log', 0);
更新index.js,哪里更新?找老师的源码

controller


@PostMapping("/update/{spuId}")
public R updateSpuAttr(@PathVariable("spuId") Long spuId,
                       @RequestBody List<ProductAttrValueEntity> entities){
    productAttrValueService.updateSpuAttr(spuId,entities);
    return R.ok();
}

impl


这里的修改其实是先把原来的spu_id下的属性都删除掉


之后在把前端传来的属性集合进行批量保存


@Transactional(rollbackFor = Exception.class)
@Override
public void updateSpuAttr(Long spuId, List<ProductAttrValueEntity> entities) {
    //1、删除spuId之前对应的所有属性
    this.baseMapper.delete(new QueryWrapper<ProductAttrValueEntity>().eq("spu_id",spuId));
    //2、添加商品规格信息
    List<ProductAttrValueEntity> collect = entities.stream().map(item -> {
        item.setSpuId(spuId);
        return item;
    }).collect(Collectors.toList());
    //批量新增
    this.saveBatch(collect);
}

销售属性详情

显示销售属性

如图http://localhost:88/api/product/attr/sale/list/0?t=1660181297434&page=1&limit=10&key=这个接口有问题!


所以我们就去后端改这个接口即可!


5836f39d798e2fd94ffd0bf6ec2c98d7_74ef8de982ed8badfae0452f81516775.png


controller


规格参数和销售参数的区别在于type的值,type为 1是规格参数,type为0是销售参数


这里采用一个方法当两个来用!


dcd15aa3b28c039312b0cf06378f373c_ca5be51f611f8409a7e4970138620a46.png


@GetMapping("/{attrType}/list/{catelogId}")
public R baseAttrList(@RequestParam Map<String, Object> params,
                      @PathVariable("attrType") String type,
                      @PathVariable("catelogId") Integer catelogId) {
    PageUtils page = attrService.queryBaseAttrPage(params, type, catelogId);
    return R.ok().put("page", page);
}

service


在原来对规格参数的基础上加了限制条件,如果是规格参数那就是WHERE attr_type = 1,否则就是WHERE attr_type = 0;


下面的逻辑和查询规格参数一致,都要模糊查询


这里为了使代码更通用,1和0的值我们写一个常量来控制,如过后期换值了我们直接更改常量的值即可


ProductConstant


package com.caq.common.constant;
public class ProductConstant {
    public enum AttrEnum{
        ATTR_TYPE_BASE(1,"基本属性"),
        ATTR_TYPE_SALE(0,"销售属性");
        private int code;
        private String msg;
        AttrEnum(int code,String msg){
            this.code = code;
            this.msg = msg;
        }
        public int getCode(){
            return code;
        }
        public String getMsg(){
            return msg;
        }
    }
}

在原来对规格参数的基础上加了限制条件,如果是规格参数那就是WHERE attr_type = 1,否则就是WHERE attr_type = 0;


@Override
    public PageUtils queryBaseAttrPage(Map<String, Object> params, String type, Integer catelogId) {
        QueryWrapper<AttrEntity> wrapper = new QueryWrapper<AttrEntity>()
                .eq("attr_type", "base".equalsIgnoreCase(type) ? ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() : ProductConstant.AttrEnum.ATTR_TYPE_SALE.getCode());
        if (catelogId != 0) {
            //如果不是一级分类,那么查询的时候加上where catelog_id = ?
            //IgnoreCase忽略大小写
            wrapper.eq("catelog_id", catelogId);
        }
        //多条件模糊查询
        //搜索框里的key不但可以对catelog_id进行模糊查询,对attr_name也模糊查询
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            wrapper.eq("attr_id", key).or().like("attr_name", key);
        }
        //多条件分页查询
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                wrapper);
        PageUtils pageUtils = new PageUtils(page);
        List<AttrEntity> list = page.getRecords();
//        .map()这个方法是对被筛选过后的流进行映射,一般是对属性进行赋值。
        List<AttrRespVo> resultList = list.stream().map(item -> {
            AttrRespVo attrRespvo = new AttrRespVo();
            BeanUtils.copyProperties(item, attrRespvo);
            AttrAttrgroupRelationEntity attrgroupRelationEntity = relationService.
                    getOne(new QueryWrapper<AttrAttrgroupRelationEntity>()
                            .eq("attr_id", item.getAttrId()));
            if (attrgroupRelationEntity != null) {
                //attrgroupRelationEntity.getAttrGroupId()也可以,这里可以直接放进去对象
                AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrgroupRelationEntity);
                attrRespvo.setGroupName(attrGroupEntity.getAttrGroupName());
            }
            CategoryEntity categoryEntity = categoryService.getById(item.getCatelogId());
            if (categoryEntity != null) {
                attrRespvo.setCatelogName(categoryEntity.getName());
            }
            //返回最后的封装结果
            return attrRespvo;
        }).collect(Collectors.toList());
        //返回的结果是一个集合
        pageUtils.setList(resultList);
//        返回分页后的集合对象
        return pageUtils;
    }

销售属性回显

可以看到,销售属性回显是不需要所属分组的


但是销售属性和规格参数用的是同一个回显方法,我们也进行更改,只有是规格参数的时候才进行分组回显!


6c392e1eb2f105072f783fff8c01675a_a385d747bab5c37a25f3eea078ebdc27.png


在原分组回显的逻辑上加上判断,后面逻辑不变!


if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
    ...
}

2856a9a4af5c3826edc1f128bf7abf34_610c7bbd019d784ec179c79f8cdc31e1.png


修改销售属性

销售属性和规格参数用的是同一个修改方法,销售属性进行修改时,会对关联表进行一个级联更新,但销售属性不需要


所以也在对关联表级联更新的时候进行判断,只有销售属性修改的时候才进行级联更新!


if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
    ...
}

7c332805934ae93f1d06c843b51d14a2_dd659e254b74ca3c18ec218d35f51c69.png


保存销售属性

销售属性和规格参数用的是同一个保存方法,销售属性进行保存时,会对关联表进行一个级联保存,但销售属性不需要


所以也在对关联表级联保存的时候进行判断,只有销售属性保存的时候才进行级联保存!


if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
    ...
}

93db0a36e9b9d6a06b2ee93613fbaf62_96c8f6eaa690c15c185b9dcdeadbbe60.png

相关文章
|
2月前
|
XML 前端开发 Java
谷粒商城笔记+踩坑(5)——商品服务-属性分组、品牌关联分类,spu+sku+分页拦截器
SPU和SKU、属性分组的增删改查、QueryWrapper的and和or用法、获取当前品牌关联的所有分类
谷粒商城笔记+踩坑(5)——商品服务-属性分组、品牌关联分类,spu+sku+分页拦截器
|
3月前
|
Java API 开发工具
如何通过淘宝商品详情接口实现商品 SKU、优惠价、价格等参数的实时更新?
要合法获取淘宝商品详情数据,首先需通过淘宝开放平台注册开发者账号并获得App Key与App Secret。接着根据业务需求申请对应的商品详情数据接口权限,并通过官方文档了解接口详情。获取访问令牌后,按照文档构建请求URL并附加必要参数及令牌以调用接口。此外,考虑使用淘宝提供的SDK简化开发流程,如Python SDK等。体验API:b.mrw.so/2Pv6Qu。
|
3月前
|
数据采集 API 开发工具
淘系商品详情数据解析(属性youhui券sku详情图等)API接口开发系列
在电商领域,特别是像淘宝(淘系)这样的平台,商品详情数据对于商家、开发者以及数据分析师来说至关重要。这些数据包括但不限于商品属性、优惠券信息、SKU(Stock Keeping Unit)详情、商品图片、售后保障等。然而,直接访问淘宝的内部API接口通常需要特定的权限和认证,这通常只对淘宝的合作伙伴或内部开发者开放。 不过,对于需要这些数据的第三方开发者或商家,有几种方式可以间接获取或解析淘系商品详情数据: ——在成长的路上,我们都是同行者。这篇关于商品详情API接口的文章,希望能帮助到您。期待与您继续分享更多API接口的知识,请记得关注Anzexi58哦!
|
3月前
|
数据采集 JSON API
淘系商品详情图属性sku价格解析,API接口系列
淘宝(Taobao)作为阿里巴巴集团旗下的电商平台,其商品详情图、属性、SKU和价格的采集通常不直接通过公开的API接口来实现,因为淘宝的API主要面向商家和开发者提供店铺管理、订单处理、物流查询等功能,并不直接提供商品详情页的完整数据抓取接口
|
3月前
|
XML 存储 API
电商商品详情页面的获取,详情图属性sku价格的采集,API接口系列
在电商平台上,商品详情页面的获取,包括详情图、属性、SKU(Stock Keeping Unit,库存量单位)、价格等信息的采集,通常可以通过多种方式实现,其中之一是利用电商平台提供的API接口。以下是一个基于通用流程的概述,用于说明如何通过API接口系列来采集这些信息。
|
5月前
|
存储 JSON API
批量采集抖音商品详情数据:推荐你使用API(通过商品id取商品详情商品主图sku属性)
批量采集抖音商品详情,建议使用API接口。步骤包括:注册抖音开放平台获取App Key和Secret,调用商品详情API接口传入商品ID及相关参数,解析返回的JSON获取商品信息(如名称、价格、主图和SKU)。此外,接口列表提供商品搜索、销售量查询、历史价格、订单管理等多种功能。已封装的API接口地址:c0b.cc/R4rbK2,可测试并联系获取SDK文件。
|
6月前
|
存储 数据采集 JSON
电商API分享:如何批量获取商品详情页数据(属性图价格sku视频评论)
电商API(应用程序接口)通常提供了丰富的数据获取功能,使开发者能够方便地获取商品详情页的各种数据,包括商品属性、图片、价格、SKU(库存量单位)、视频以及评论等。以下是一个基本的步骤指南,用于通过电商API批量获取商品详情页数据:
|
SQL 前端开发 测试技术
谷粒商城--SPU和SKU(属性分组、规格参数、销售属性)-1
谷粒商城--SPU和SKU(属性分组、规格参数、销售属性)
207 0
|
JSON 前端开发 Java
谷粒商城--SPU和SKU(分组与属性关联、发布商品、仓库服务)-2
谷粒商城--SPU和SKU(分组与属性关联、发布商品、仓库服务)
92 0
|
测试技术 API 微服务
谷粒商城--SPU和SKU(分组与属性关联、发布商品、仓库服务)-3
谷粒商城--SPU和SKU(分组与属性关联、发布商品、仓库服务)
68 0