guliMall 分布式基础篇-- 平台属性

   <delete id="deleteBatchRelation">
     DELETE FROM pms_attr_attrgroup_relation WHERE
        <foreach collection="entities" item="item" separator=" OR ">
            (attr_id=#{item.attrId} AND attr_group_id=#{item.attrGroupId})
        </foreach>

    </delete>

平台属性

1. 规格新增与VO

1.1 对属性分组进行模糊查询功能

修改AttrGroupServiceImpl

    //对分类属性进行查询和模糊查询功能
    @Override
    public PageUtils queryPage(Map<String, Object> params, Long catelogId) {
        // 检索条件多匹配-- 模糊查询
        String key = (String) params.getOrDefault("key", null);
        QueryWrapper<AttrGroupEntity> wrapper = new QueryWrapper<AttrGroupEntity>();
        if(!StringUtils.isEmpty(key)){
            wrapper.and((obj)->{
                obj.eq("attr_group_id",key).or().like("attr_group_name",key);
            });
        }
        if(catelogId.equals(0L)){
            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);
        }

    }

 1.2 规格参数新增& 关联参数所在分组

逆向生成的规格参数新增,只有基础的新增,保存的有所属分类的信息,没有添加所属分组的关联关系。

VO值对象:接受页面传递来的数据,封装对象

创建包 com/atguigu/gulimall/product/VO  用来存储VO值

因为需要添加数据库中没有的字段,在entity中添加不符合代码规范,所以我们可以使用VO来进行存储数据。

将 AttrEntity 中的数据传入到 AttrVo 中

@Data
public class AttrVo {
    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;
    /**
     * 值类型[0-为单个值,1-可以选择多个值]
     */
    private Integer valueType;
    /**
     * 所属分组
     */
    private Long attrGroupId;
}

在 AttrController 修改对应的 AttrEntity 实体 为 AttrVo

@RestController
@RequestMapping("product/attr")
public class AttrController {
    @Autowired
    private AttrService attrService;
 
   
    /**
     * 保存
     */
    @RequestMapping("/save")
 
    public R save(@RequestBody AttrVo attr){
		attrService.saveAttr(attr);
 
        return R.ok();
    }
}

在规格参数新增过程中添加 维护attr 与分组的 关系,使用AttrVo

public interface AttrService extends IService<AttrEntity> {

    PageUtils queryPage(Map<String, Object> params);

    //新增规格参数与分组的关联关系
    void saveAttr(AttrVo attr);
}

 在AttrServiceImpl 新增功能中引入 AttrAttrgroupRelationDao ,来维护属性与属性分组的关系


@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    private AttrAttrgroupRelationDao RelationDao;

   

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveAttr(AttrVo attr) {
        // 1. 保存基础数据
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attr,attrEntity);
        this.save(attrEntity);
        // 2. 维护关联关系 属性与属性分组
        AttrAttrgroupRelationEntity RelationEntity = new AttrAttrgroupRelationEntity();
        RelationEntity.setAttrId(attrEntity.getAttrId());
        RelationEntity.setAttrGroupId(attr.getAttrGroupId());
        RelationDao.insert(RelationEntity);
    }


}

Attr 与AttrGroup 关联关系表 

2. 规格参数列表

新增Vo 类 AttrRespVo 

因为在AttrEntity 中没有 所在分组名字和所在分类名字,我们需要在规格参数列表的详细信息中展示出来。我们可以直接新增Vo类 AttrRespVo 来继承AttrVo

@Data
public class AttrRespVo extends AttrVo{

    /**
     * 所属分组名称
     */
    private String groupName;
    /**
     * 所属分类名称
     */
    private String catelogName;
    
}

AttrController 新增展示列表方法

@RestController
@RequestMapping("product/attr")
public class AttrController {

    @Autowired
    private AttrService attrService;

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

 attrService新增 queryBaseAttrPage 方法

public interface AttrService extends IService<AttrEntity> {

    PageUtils queryPage(Map<String, Object> params);

    //新增规格参数与分组的关联关系
    void saveAttr(AttrVo attr);

    PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId);
}

AttrServiceImpl 继承接口 AttrService

在AttrServiceImpl实现queryBaseAttrPage 方法中,通过查询表pms_attr_attrgroup_relation 的AttrId和AttrGroupId来分别查询pms_attr 和 pms_attr_group 中属性所在分组和分类的名字

@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    private AttrAttrgroupRelationDao RelationDao;

    @Resource
    private AttrGroupDao attrGroupDao;

    @Resource
    private CategoryDao categoryDao;

    @Override
    public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId) {
        QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<>();
        if(catelogId!=0L){
            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> attrRespVoList = records.stream().map((attrEntity) -> {
            AttrRespVo attrRespVo = new AttrRespVo();
            BeanUtils.copyProperties(attrEntity, attrRespVo);
            // 所属分组
            AttrAttrgroupRelationEntity attr_id = RelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getAttrId()));
            // 可能属性与属性分组没有关联关系
            if (attr_id != null) {
                AttrGroupEntity groupEntity = attrGroupDao.selectById(attr_id.getAttrGroupId());
                attrRespVo.setGroupName(groupEntity.getAttrGroupName());
            }
            // 所属分类
            CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
            if (categoryEntity != null) {
                attrRespVo.setCatelogName(categoryEntity.getName());
            }
            return attrRespVo;
        }).collect(Collectors.toList());
        pageUtils.setList(attrRespVoList);
        return pageUtils;
    }



}

2. 规格修改

2.1 回显规格信息

 在AttrRespVo 中新增分类路径字段,用来回显规格中分类的数据。

AttrRespVo 包含了所有规格所有数据

@Data
public class AttrRespVo extends AttrVo{

    /**
     * 所属分组名称
     */
    private String groupName;
    /**
     * 所属分类名称
     */
    private String catelogName;

    /**
     * 所属分类的路径
     */
    private Long[] catelogPath;

}

AttrController 层回显信息,创建新方法AttrService.getAttrInfo

@RestController
@RequestMapping("product/attr")
public class AttrController {

    @Autowired
    private AttrService attrService;

    /**
     * 修改回显信息
     */
    @RequestMapping("/info/{attrId}")
    public R info(@PathVariable("attrId") Long attrId){
        //AttrEntity attr = attrService.getById(attrId);
        AttrRespVo attrRespVo = attrService.getAttrInfo(attrId);
        return R.ok().put("attr", attrRespVo);
    }
}
public interface AttrService extends IService<AttrEntity> {


    AttrRespVo getAttrInfo(Long attrId);
}

AttrServiceImpl 继承接口

@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    private AttrAttrgroupRelationDao RelationDao;

    @Resource
    private AttrGroupDao attrGroupDao;
    @Resource
    private CategoryDao categoryDao;

    @Autowired
    private CategoryService categoryService;

    @Override
    public AttrRespVo getAttrInfo(Long attrId) {
        AttrEntity attrEntity = this.getById(attrId);
        AttrRespVo attrRespVo = new AttrRespVo();
        BeanUtils.copyProperties(attrEntity, attrRespVo);
        if (attrEntity.getCatelogId() != null) {
            // 所属分类
            Long[] catelogPath = categoryService.findCatelogPath(attrEntity.getCatelogId());
            attrRespVo.setCatelogPath(catelogPath);
            CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
            if (categoryEntity != null) {
                attrRespVo.setCatelogName(categoryEntity.getName());
            }
        }
        // 所属分组
        AttrAttrgroupRelationEntity attrAttrgroupRelation = RelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId));
        // 可能属性与属性分组没有关联关系
        if (attrAttrgroupRelation != null) {
            attrRespVo.setAttrGroupId(attrAttrgroupRelation.getAttrGroupId());
            AttrGroupEntity groupEntity = attrGroupDao.selectById(attrAttrgroupRelation.getAttrGroupId());
            if (groupEntity != null) {
                attrRespVo.setGroupName(groupEntity.getAttrGroupName());
            }

        }
        return attrRespVo;
    }

}

 回显分类和分组信息

 2.2 规格信息修改

AttrController 进行规格参数修改,新增updateAttr 方法

@RestController
@RequestMapping("product/attr")
public class AttrController {

    @Autowired
    private AttrService attrService;

    /**
     * 规格参数修改
     */
    @RequestMapping("/update")

    public R update(@RequestBody AttrVo attr){
        //attrService.updateById(attr);
        attrService.updateAttr(attr);  //新增修改规格属性方法
        return R.ok();
    }
}
public interface AttrService extends IService<AttrEntity> {

  // 规格参数修改
    void updateAttr(AttrVo attr);
}

AttrServiceImpl 实现update方法,主要有两部分,当分类或者分组数据为空时。此时我们可以使用insert方法来新增分类或者分组 

@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    private AttrAttrgroupRelationDao RelationDao;

    @Resource
    private AttrGroupDao attrGroupDao;

    @Resource
    private CategoryDao categoryDao;

    @Autowired
    private CategoryService categoryService;

    //规格参数修改功能
    @Override
    public void updateAttr(AttrVo attr) {
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attr,attrEntity);
        // 修改属性
        this.updateById(attrEntity);
        // 修改属性和属性分组关系
        if(attr.getAttrGroupId() != null) {
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = RelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId()));
            if(attrAttrgroupRelationEntity != null && !attr.getAttrGroupId().equals(attrAttrgroupRelationEntity.getAttrGroupId())){
                // 修改
                attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
                RelationDao.updateById(attrAttrgroupRelationEntity);
            }else {
                // 不存在属性和属性分组关系,新增
                AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
                relationEntity.setAttrId(attr.getAttrId());
                relationEntity.setAttrGroupId(attr.getAttrGroupId());
                RelationDao.insert(relationEntity);
            }
        }

    }
}

 2.3 销售属性维护

修改pms_attr属性表的attr_type字段的注释为属性类型[0-销售属性,1-基本属性]。
 
修改AttrController控制层接口baseAttrList:
修改请求路径,添加路径参数attrType
    @GetMapping("/base/list/{catelogId}")改为
    @GetMapping("/{attrType}/list/{catelogId}")
 
由于销售属性和规格参数公用查询、新增、修改回显、修改接口,销售属性和规格参数的不同在于没有
所属分组,在这些接口通过属性类型attrType判断是否需要操作所属分组。
 
在gulimall-common模块,在ProductConstant类中定义AttrEnum枚举类代替常量区分属性类型。

 销售属性与基本属性(规格参数)的信息基本一致,所以我们可以在基本属性的方法基础上,进行 if 选择。

//规格参数和销售属性显示列表信息,在common模块中定义一个attrtype类。
    //当attrtype为 1 时为销售属性   为 0 时为基本属性
    //所以我们需要重构 queryBaseAttrPage 方法。添加一个 type 参数
    @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);
    }

common模块中定义常量,当我们修改常量时就可以在common中进行修改。

package com.atguigu.Constant;

/**
 * @author wen
 * @createDate 2023/3/31 13:41
 * @description 产品模块常量类
 */
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;
        }
    }
}
public interface AttrService extends IService<AttrEntity> {


    //根据分组id查询所有的属性
    List<AttrEntity> getRelationAttr(Long attrGroupId);
}

@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    private AttrAttrgroupRelationDao RelationDao;

    @Resource
    private AttrGroupDao attrGroupDao;
    @Resource
    private CategoryDao categoryDao;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private AttrAttrgroupRelationDao attrAttrgroupRelationDao;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<AttrEntity> page = this.page(
                new Query<AttrEntity>().getPage(params),
                new QueryWrapper<AttrEntity>()
        );

        return new PageUtils(page);
    }

    //新增数据
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveAttr(AttrVo attr) {
        // 1. 保存基础数据
        AttrEntity attrEntity = new AttrEntity();
        BeanUtils.copyProperties(attr,attrEntity);
        this.save(attrEntity);
        // 2. 维护关联关系 属性与属性分组 attr.getAttrType() = 1时 基本属性
        if(attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() && attr.getAttrGroupId() != null) {
            AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = new AttrAttrgroupRelationEntity();
            attrAttrgroupRelationEntity.setAttrId(attrEntity.getAttrId());
            attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
            attrAttrgroupRelationDao.insert(attrAttrgroupRelationEntity);
        }
    }

    @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!=0L){
            queryWrapper.eq("catelog_id",catelogId);
        }
        String key = (String) params.get("key");

        //通过Wrapper来存储AttrEntity实体类数据,当搜索框中的数据不为空时
        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> attrRespVoList = records.stream().map((attrEntity) -> {
            AttrRespVo attrRespVo = new AttrRespVo();
            BeanUtils.copyProperties(attrEntity, attrRespVo);
            // 所属分组,销售属性没有分组,所以不处理分组事件
            if("base".equalsIgnoreCase(type)) {
                AttrAttrgroupRelationEntity attr_id = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getAttrId()));
                // 可能属性与属性分组没有关联关系
                if (attr_id != null && attr_id.getAttrGroupId() != null) {
                    AttrGroupEntity groupEntity = attrGroupDao.selectById(attr_id.getAttrGroupId());
                    attrRespVo.setGroupName(groupEntity.getAttrGroupName());
                }
            }
            // 所属分类
            CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
            if (categoryEntity != null) {
                attrRespVo.setCatelogName(categoryEntity.getName());
            }
            return attrRespVo;
        }).collect(Collectors.toList());
        pageUtils.setList(attrRespVoList);
        return pageUtils;
    }

    //获取规格参数(基本信息)和销售属性
    @Override
    public AttrRespVo getAttrInfo(Long attrId) {
        AttrEntity attrEntity = this.getById(attrId);  //通过属性Id 获取属性表中对应的实体信息
        AttrRespVo attrRespVo = new AttrRespVo();   //创建一个Vo实体,用来返回对应的回显信息
        BeanUtils.copyProperties(attrEntity, attrRespVo);  //将获取的实体信息复制到Vo 实体中
        if (attrEntity.getCatelogId() != null) {    //当获取的分类id不为0时
            // 所属分类
            Long[] catelogPath = categoryService.findCatelogPath(attrEntity.getCatelogId());  //查找分类路径节点
            attrRespVo.setCatelogPath(catelogPath);   //将路径节点放到attrRespVo中
            CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());  //通过获取的分类id获取分类实体
            if (categoryEntity != null) {   //当分类id不为0时
                attrRespVo.setCatelogName(categoryEntity.getName());   //获取对应的分类的名字
            }
        }
        // 所属分组
        if(attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()){
            AttrAttrgroupRelationEntity attrAttrgroupRelation = RelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId));
            // 可能属性与属性分组没有关联关系
            if (attrAttrgroupRelation != null) {
                attrRespVo.setAttrGroupId(attrAttrgroupRelation.getAttrGroupId());
                AttrGroupEntity groupEntity = attrGroupDao.selectById(attrAttrgroupRelation.getAttrGroupId());
                if (groupEntity != null) {
                    attrRespVo.setGroupName(groupEntity.getAttrGroupName());
                }

            }
        }

        return attrRespVo;
    }

   //修改基本信息(规格参数)和销售属性信息
    @Transactional(rollbackFor = Exception.class)
    @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()) {
            if (attr.getAttrGroupId() != null) {
                AttrAttrgroupRelationEntity attrAttrgroupRelationEntity = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId()));
                if (attrAttrgroupRelationEntity != null) {
                    if(!attr.getAttrGroupId().equals(attrAttrgroupRelationEntity.getAttrGroupId())) {
                        // 修改
                        attrAttrgroupRelationEntity.setAttrGroupId(attr.getAttrGroupId());
                        attrAttrgroupRelationDao.updateById(attrAttrgroupRelationEntity);
                    }
                } else {
                    // 不存在属性和属性分组关系,新增
                    AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
                    relationEntity.setAttrId(attr.getAttrId());
                    relationEntity.setAttrGroupId(attr.getAttrGroupId());
                    attrAttrgroupRelationDao.insert(relationEntity);
                }
            }
        }

    }


    /**
     * 根据分组id查询所有关联的基本属性
     * @param attrGroupId
     * @return
     */
    @Override
    public List<AttrEntity> getRelationAttr(Long attrGroupId) {
        List<AttrAttrgroupRelationEntity> relationEntities = attrAttrgroupRelationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id", attrGroupId));
        List<Long> attrIds = relationEntities.stream().map(relationEntitie -> {
            return relationEntitie.getAttrId();
        }).collect(Collectors.toList());
        if(attrIds == null || attrIds.size()==0){
            return null;
        }
        List<AttrEntity> attrEntities = this.listByIds(attrIds);
        return attrEntities;
    }


}

3. 查询分组关联属性&删除关联

3.1 查询分组与属性关联
@RestController
@RequestMapping("product/attrgroup")
public class AttrGroupController {
    @Autowired
    private AttrGroupService attrGroupService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private AttrService attrService;
 
    /**
     * 根据属性分组ID查询所有关联的属性
     * @return
     */
    @GetMapping("/{attrgroupId}/attr/relation")
    public R attrRelation(@PathVariable("attrgroupId") Long attrGroupId){
        List<AttrEntity> attrEntities = attrService.getRelationAttr(attrGroupId);
        return R.ok().put("data",attrEntities);
    }
}
public interface AttrService extends IService<AttrEntity> {
    ...
 
    List<AttrEntity> getRelationAttr(Long attrGroupId);
}
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
 
    @Resource
    private AttrAttrgroupRelationDao attrAttrgroupRelationDao;
    @Resource
    private AttrGroupDao attrGroupDao;
    @Resource
    private CategoryDao categoryDao;
    @Resource
    private CategoryService categoryService;
    
    /**
     * 根据分组id查询所有关联的基本属性
     * @param attrGroupId
     * @return
     */
    @Override
    public List<AttrEntity> getRelationAttr(Long attrGroupId) {
      List<AttrAttrgroupRelationEntity> relationEntities = attrAttrgroupRelationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id", attrGroupId));
        List<Long> attrIds = relationEntities.stream().map(relationEntitie -> {
            return relationEntitie.getAttrId();
        }).collect(Collectors.toList());
        if(attrIds == null || attrIds.size()==0){
            return null;
        }
        List<AttrEntity> attrEntities = this.listByIds(attrIds);
        return attrEntities;
    }
 
}
3.2 删除关联&批量删除
@RestController
@RequestMapping("product/attrgroup")
public class AttrGroupController {
    @Autowired
    private AttrGroupService attrGroupService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private AttrService attrService;
 
    @PostMapping("/attr/relation/delete")
    public R deleteRelation(@RequestBody AttrGroupRelationVo[] vos){
        attrService.deleteRelation(vos);
        return R.ok();
    }
}
public interface AttrService extends IService<AttrEntity> {
    ...
 
    void deleteRelation(AttrGroupRelationVo[] vos);
}
@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {
 
    @Resource
    private AttrAttrgroupRelationDao attrAttrgroupRelationDao;
    @Resource
    private AttrGroupDao attrGroupDao;
    @Resource
    private CategoryDao categoryDao;
    @Resource
    private CategoryService categoryService;
 
    /**
     * 删除属性分组与属性关系
     * @param vos
     */
    @Override
    public void deleteRelation(AttrGroupRelationVo[] vos) {
        List<AttrAttrgroupRelationEntity> entityList = Arrays.asList(vos).stream().map(vo -> {
            AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
            BeanUtils.copyProperties(vo, relationEntity);
            return relationEntity;
        }).collect(Collectors.toList());
        attrAttrgroupRelationDao.deleteBatchRelation(entityList);
    }
 
}
@Mapper
public interface AttrAttrgroupRelationDao extends BaseMapper<AttrAttrgroupRelationEntity> {

    void deleteBatchRelation(@Param("entities") List<AttrAttrgroupRelationEntity> entityList);
}
   <delete id="deleteBatchRelation">
     DELETE FROM pms_attr_attrgroup_relation WHERE
        <foreach collection="entities" item="item" separator=" OR ">
            (attr_id=#{item.attrId} AND attr_group_id=#{item.attrGroupId})
        </foreach>

    </delete>

4.  查询分组未关联的属性

在属性分组页面-->点击关联-->新增关联  展示在同一分类下,没有被其他分组关联的属性。

ArreGroupController

@RestController
@RequestMapping("product/attrgroup")
public class AttrGroupController {
    @Autowired
    private AttrGroupService attrGroupService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private AttrService attrService;

    @Autowired
    private AttrAttrgroupRelationService attrAttrgroupRelationService;

    //查询分组未关联的基本属性(一个分类代表多个分组,一个分组代表多个分类)
    //可以进行新增的基本属性
    @GetMapping("/{attrgroupId}/noattr/relation")
    public R attrNoRelation(@PathVariable("attrgroupId") Long attrGroupId,
                            @RequestParam Map<String, Object> params){
        PageUtils page = attrService.getNoRelationAttr(params,attrGroupId);

        return R.ok().put("page",page);
    }
}
public interface AttrService extends IService<AttrEntity> {



    //查询分组未关联的基本属性
    PageUtils getNoRelationAttr(Map<String, Object> params, Long attrGroupId);
}


@Service("attrService")
public class AttrServiceImpl extends ServiceImpl<AttrDao, AttrEntity> implements AttrService {

    @Autowired
    private AttrAttrgroupRelationDao RelationDao;

    @Resource
    private AttrGroupDao attrGroupDao;
    @Resource
    private CategoryDao categoryDao;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private AttrAttrgroupRelationDao attrAttrgroupRelationDao;

    /**
     * 获取分组所属分类下未关联的属性
     *
     * @param params
     * @param attrGroupId
     * @return
     */
    @Override
    public PageUtils getNoRelationAttr(Map<String, Object> params, Long attrGroupId) {
        // 当前分组只能关联自己所属分类下其他分组未关联的属性
        AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrGroupId);
        // 获取当前分组的分类
        Long catelogId = attrGroupEntity.getCatelogId();
        // 获取其他分组关联的属性
        // 1)获取同一分类下的所有分组(包括当前分组)
        List<AttrGroupEntity> attrGroupEntities = attrGroupDao.selectList(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId));
        List<Long> appGroupIds = attrGroupEntities.stream().map(item -> {
            return item.getAttrGroupId();
        }).collect(Collectors.toList());
        // 2)这些分组关联的属性
        List<AttrAttrgroupRelationEntity> relationEntities = attrAttrgroupRelationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().in("attr_group_id", appGroupIds));
        List<Long> attrIds = relationEntities.stream().map(relationEntitie -> {
            return relationEntitie.getAttrId();
        }).collect(Collectors.toList());
        // 3)当前分类下去除这些属性
        // 当前分类下所有的基础属性
        //QueryWrapper 主要用来查询功能,自身的内部属性 entity 也用于生成 where 条件 及 LambdaQueryWrappe
        QueryWrapper<AttrEntity> wrapper = new QueryWrapper<AttrEntity>().eq("catelog_id", catelogId).eq("attr_type", ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode());
        if (attrIds != null && attrIds.size() > 0) {
            // 去除已经关联的属性
            wrapper.notIn("attr_id", attrIds);
        }

        //搜索框功能
        // 拼接条件查询
        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;
    }


}

5. 新增分组与属性关联

当点击确认新增时,属性分组与属性关联成功。

@RestController
@RequestMapping("product/attrgroup")
public class AttrGroupController {
    @Autowired
    private AttrGroupService attrGroupService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private AttrService attrService;
    @Autowired
    private AttrAttrgroupRelationService attrAttrgroupRelationService;
 
    @PostMapping("/attr/relation")
    public R addRelation(@RequestBody List<AttrGroupRelationVo> vos){
        // 添加属性分组与属性关联关系
        attrAttrgroupRelationService.saveBatch(vos);
        return R.ok();
    }
}
public interface AttrAttrgroupRelationService extends IService<AttrAttrgroupRelationEntity> {
 
    ...
 
    void saveBatch(List<AttrGroupRelationVo> vos);
}
@Service("attrAttrgroupRelationService")
public class AttrAttrgroupRelationServiceImpl extends ServiceImpl<AttrAttrgroupRelationDao, AttrAttrgroupRelationEntity> implements AttrAttrgroupRelationService {
 
    @Override
    public void saveBatch(List<AttrGroupRelationVo> vos) {
        List<AttrAttrgroupRelationEntity> relationEntityList = vos.stream().map(vo -> {
            AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
            BeanUtils.copyProperties(vo, relationEntity);
            return relationEntity;
        }).collect(Collectors.toList());
        this.saveBatch(relationEntityList);
    }
 
}

 新增商品

1. 调试会员等级相关接口

会员等级是在 member 项目中实现的。

所以我们要对 gulimall-member 进行关于nacos 的配置

spring:

  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: gulimall-member

 在gulimall-gateway 中进行配置

将member模块的项目请求交给路由转发,由路由交给renrenfast处理。

        - id: member_route
          uri: lb://gulimall-member
          predicates:
            - Path=/api/member/**
          filters:
            - RewritePath=/api/?(?<segment>.*), /$\{segment}

进行新增会员等级

2. 获取分类关联的品牌

前台有关pubsub、publish报错,导致无法发送查询品牌信息的请求:
(1)npm install --save pubsub-js
(2)在src下的main.js中引用:
    1)import PubSub from 'pubsub-js'
    2)Vue.prototype.PubSub = PubSub

在商品发布页面,当我们获取商品对应的分类时,同时也能获取到分类对应的关联品牌

一个分类可以对应多个品牌,一个品牌可以对应多个属性分组,一个属性分组可以对应多个属性

CategoryBrandRelationController

@RestController
@RequestMapping("product/categorybrandrelation")
public class CategoryBrandRelationController {

    @Autowired
    private CategoryBrandRelationService categoryBrandRelationService;


/**
     * 获取分类关联品牌
     * /product/categorybrandrelation/brands/list
     */
    @GetMapping("/brands/list")
    public R relationBrandList(@RequestParam(value = "catId",required = true) Long catId){
        List<BrandEntity> brandEntities = categoryBrandRelationService.getBrandCatId(catId);
        List<BrandVo> collect = brandEntities.stream().map(item -> {   //将获取的实体类封装起来,转化为想要的数据。
            BrandVo brandVo = new BrandVo();  //新建一个实体类 BrandVo
            brandVo.setBrandId(item.getBrandId());   //BrandVo 从item 中获取想要的品牌 Id 和品牌姓名
            brandVo.setBrandName(item.getName());
            return brandVo;
        }).collect(Collectors.toList());   //‘将数据收集起来封装到collect 中
        return R.ok().put("data", collect);
    }

}
@Data
public class AttrGroupRelationVo {

    private Long attrId;
    private Long attrGroupId;

}
public interface CategoryBrandRelationService extends IService<CategoryBrandRelationEntity> 
{


    //获取某分类下所关联的所有品牌
    List<BrandEntity> getBrandCatId(Long catId);
}
@Service("categoryBrandRelationService")
public class CategoryBrandRelationServiceImpl extends ServiceImpl<CategoryBrandRelationDao, CategoryBrandRelationEntity> implements CategoryBrandRelationService {

    @Autowired
    private CategoryDao categoryDao;

    @Autowired
    private BrandDao brandDao;

    @Resource
    private CategoryBrandRelationDao categoryBrandRelationDao;

    @Resource
    private BrandService brandService;


    //获取某分类下所关联的所有品牌
    @Override
    public List<BrandEntity> getBrandCatId(Long catId) {
        List<CategoryBrandRelationEntity> catelog_id = categoryBrandRelationDao.selectList(new QueryWrapper<CategoryBrandRelationEntity>().eq("catelog_id", catId));
        List<BrandEntity> brandEntities = catelog_id.stream().map(item -> {
            Long brandId = item.getBrandId();
            BrandEntity byId = brandService.getById(brandId);
            return byId;
        }).collect(Collectors.toList());
        return brandEntities;
    }

}

 3. 获取分类下所有分组以及属性

首先当我们完善商品的基本信息--分类信息时,在发布商品页面会出现相关联的品牌信息。

同时,我们也需要获取商品的基本信息,这个同时也可以通过分类 Id 进行查询。

我们可以通过分类 id 获取对应的属性分组和属性。

/**
     * /product/attrgroup/{catelogId}/withattr
     * 获取分类下所有的属性分组和属性, 分类与属性相关联,每一个分类下的属性大致相同
     * @param catelogId
     * @return
     */
    @GetMapping("/{catelogId}/withattr")
    public R getAttrGroupWithAttrs(@PathVariable("catelogId") Long catelogId){
        // 查询当前分类下的所有属性分组
        // 查询每个属性分组的所有属性
        List<AttrGroupWithAttrsVo> vos = attrGroupService.getAttrGroupWithAttrsByCatelogId(catelogId);
        return R.ok().put("data",vos);
    }
@Data
public class AttrGroupRelationVo {

    private Long attrId;
    private Long attrGroupId;

}
public interface AttrGroupService extends IService<AttrGroupEntity> {

    //通过分类 id 来获取对应的 属性分组以及属性 
    List<AttrGroupWithAttrsVo> getAttrGroupWithAttrsByCatelogId(Long catelogId);
}
@Service("attrGroupService")
public class AttrGroupServiceImpl extends ServiceImpl<AttrGroupDao, AttrGroupEntity> implements AttrGroupService {

    @Autowired
    private AttrService attrService;

    /**
     * 根据分类id查出所有的分组以及分组关联的属性
     * @param catelogId
     * @return
     */
    @Override
    public List<AttrGroupWithAttrsVo> getAttrGroupWithAttrsByCatelogId(Long catelogId) {
        // 1.根据分类Id查询分组
        List<AttrGroupEntity> attrGroupEntities = this.list(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId));
        // 2.根据分组查询属性
        //封装attrGroupEntities 所属组的属性信息
        List<AttrGroupWithAttrsVo> collect = attrGroupEntities.stream().map(group -> {
            AttrGroupWithAttrsVo attrsVo = new AttrGroupWithAttrsVo();
            BeanUtils.copyProperties(group, attrsVo);
            List<AttrEntity> attrs = attrService.getRelationAttr(attrsVo.getAttrGroupId());  //通过 组ID 获取属性ID
            attrsVo.setAttrs(attrs);
            return attrsVo;
        }).collect(Collectors.toList());
        return collect;
    }

}

4. 新增商品

当我们完善发布商品的信息时,我们需要存储以下页面数据

基本信息--spu 基本信息

规格参数

sku信息--基本信息+规格参数+销售属性

当我们点击完善最后一步sku基本信息,点击确认保存时

控制台会发送 json 数据,而这些jasn数据就是我们需要进行保存的数据
保存商品信息,新增vo的抽取:
(1)点击保存商品信息,复制控制台的json数据到JSON工具(https://www.bejson.com/);
(2)将控制台的数据粘贴在格式化校验输入栏;
(3)使用JSON工具将json数据转为实体;
(4)将生成的实体放在gulimall-product模块的com.wen.gulimall.product.vo包下;
(5)调整使用JSON工具生成的实体。

 

 

 商品新增Vo:

@Data
public class SpuSaveVo {
    private String spuName;
    private String spuDescription;
    private Long catalogId;
    private Long brandId;
    private BigDecimal weight;
    private int publishStatus;
    private List<String> decript;
    private List<String> images;
    private Bounds bounds;
    private List<BaseAttrs> baseAttrs;
    private List<Skus> skus;
}
@Data
public class Bounds {
    private BigDecimal buyBounds;
    private BigDecimal growBounds;
}
@Data
public class BaseAttrs {
    private Long attrId;
    private String attrValues;
    private int showDesc;
}
@Data
public class Skus {
    private List<Attr> attr;
    private String skuName;
    private BigDecimal price;
    private String skuTitle;
    private String skuSubtitle;
    private List<Images> images;
    private List<String> descar;
    private int fullCount;
    private BigDecimal discount;
    private int countStatus;
    private BigDecimal fullPrice;
    private BigDecimal reducePrice;
    private int priceStatus;
    private List<MemberPrice> memberPrice;
}
@Data
public class Images {
    private String imgUrl;
    private int defaultImg;
}
@Data
public class MemberPrice {
    private Long id;
    private String name;
    private BigDecimal price;
}

 5. 商品新增业务流程分析

保存商品信息的流程:
1. 保存spu的基本信息 ;pms_spu_info    商品基本信息
2. 保存spu的描述图片 ;pms_spu_info_desc      商品的图片描述
3. 保存spu的图片集 ;pms_spu_images       商品的图片集
4. 保存spu的规格参数 ;pms_product_attr_value  商品的规格参数
5. 保存spu的积分信息 ;gulimall_sms-》sms_spu_bounds    

6. 保存当前spu对应的所有sku信息 ;
6.1 sku的基本信息 ;pms_sku_info
6.2 sku的图片信息 ;pms_sku_images
6.2 sku的销售属性信息 ;pms_sku_sale_attr_value
6.2 sku的优惠、满减等信息 ;gulimall_sms-》sms_sku_ladder/sms_sku_full_reduction/sms_member_price

6. 保存 spu 基本信息

首先我们需要创建 保存spu和sku的请求方法

由于sku是spu信息对应的,所以我们可以在SpuInfoService 中进行保存数据

 我们在 SkuInfoController 中进行 SpuInfoService的save 请求

@RestController
@RequestMapping("product/skuinfo")
public class SkuInfoController {
    @Autowired
    private SkuInfoService skuInfoService;

    @Autowired
    private SpuInfoService spuInfoService;


    /**
     * 保存
     */
    @RequestMapping("/save")
    public R save(@RequestBody SpuSaveVo vo){
//		skuInfoService.save(skuInfo);
        spuInfoService.saveSpuInfo(vo);
        return R.ok();
    }

   

}
public interface SpuInfoService extends IService<SpuInfoEntity> {

    //保存 spu和sku的所有信息
    void saveSpuInfo(SpuSaveVo vo);

}

@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Resource
    private SpuInfoDescService spuInfoDescService;

    @Resource
    private SpuImagesService imagesService;

    @Resource
    private AttrService attrService;

    @Resource
    private ProductAttrValueService productAttrValueService;

    @Resource
    private SkuInfoService skuInfoService;

    @Resource
    private SkuImagesService skuImagesService;

    @Resource
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSpuInfo(SpuSaveVo vo) {

        // 1. 保存spu的基本信息 ;pms_spu_info
        SpuInfoEntity InfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(vo,InfoEntity);
        InfoEntity.setCreateTime(new Date());
        InfoEntity.setUpdateTime(new Date());
        this.saveBaseSpuInfo(InfoEntity);

        // 2. 保存spu的描述图片 ;pms_spu_info_desc
        List<String> decript = vo.getDecript();
        SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
        descEntity.setSpuId(InfoEntity.getId());
        descEntity.setDecript(String.join(",",decript));
        spuInfoDescService.saveSpuInfoDesc(descEntity);

        // 3. 保存spu的图片集 ;pms_spu_images
        List<String> images = vo.getImages();
        imagesService.saveImages(InfoEntity.getId(),images);

        // 4. 保存spu的规格参数 ;pms_product_attr_value
        List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
        List<ProductAttrValueEntity> collect = baseAttrs.stream().map(attr -> {
            ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
            valueEntity.setAttrId(attr.getAttrId());
            AttrEntity byId = attrService.getById(attr.getAttrId());
            valueEntity.setAttrName(byId.getAttrName());
            valueEntity.setAttrValue(attr.getAttrValues());
            valueEntity.setSpuId(InfoEntity.getId());
            valueEntity.setQuickShow(attr.getShowDesc());
            return valueEntity;
        }).collect(Collectors.toList());
        productAttrValueService.saveProductAttr(collect);
        // 5. 保存spu的积分信息 ;gulimall_sms-》sms_spu_bounds

        // 6. 保存当前spu对应的所有sku信息 ;
        
                // 6.1 sku的基本信息 ;pms_sku_info
                

                // 6.2 sku的图片信息 ;pms_sku_images
                
                // 6.3 sku的销售属性信息 ;pms_sku_sale_attr_value
                
        }
        // 6.4 sku的优惠、满减等信息 ;gulimall_sms-》

    }

}
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Override
    public void saveBaseSpuInfo(SpuInfoEntity InfoEntity) {
        this.baseMapper.insert(InfoEntity);
    }

}
public interface SpuInfoDescService extends IService<SpuInfoDescEntity> {

    PageUtils queryPage(Map<String, Object> params);

    //保存 spu 描述图片
    void saveSpuInfoDesc(SpuInfoDescEntity descEntity);
}
public interface SpuImagesService extends IService<SpuImagesEntity> {

    PageUtils queryPage(Map<String, Object> params);

    //保存spu 图片集
    void saveImages(Long id, List<String> images);
}
public interface ProductAttrValueService extends IService<ProductAttrValueEntity> {

    PageUtils queryPage(Map<String, Object> params);

    //保存商品规格参数
    void saveProductAttr(List<ProductAttrValueEntity> collect);
}

 7. 保存 sku 基本信息

@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {

    @Resource
    private SpuInfoDescService spuInfoDescService;
    @Resource
    private SpuImagesService imagesService;
    @Resource
    private AttrService attrService;
    @Resource
    private ProductAttrValueService productAttrValueService;
    @Resource
    private SkuInfoService skuInfoService;
    @Resource
    private SkuImagesService skuImagesService;
    @Resource
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSpuInfo(SpuSaveVo vo) {

        // 1. 保存spu的基本信息 ;pms_spu_info
        SpuInfoEntity InfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(vo,InfoEntity);
        InfoEntity.setCreateTime(new Date());
        InfoEntity.setUpdateTime(new Date());
        this.saveBaseSpuInfo(InfoEntity);

        // 2. 保存spu的描述图片 ;pms_spu_info_desc
        List<String> decript = vo.getDecript();
        SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
        descEntity.setSpuId(InfoEntity.getId());
        descEntity.setDecript(String.join(",",decript));
        spuInfoDescService.saveSpuInfoDesc(descEntity);

        // 3. 保存spu的图片集 ;pms_spu_images
        List<String> images = vo.getImages();
        imagesService.saveImages(InfoEntity.getId(),images);

        // 4. 保存spu的规格参数 ;pms_product_attr_value
        List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
        List<ProductAttrValueEntity> collect = baseAttrs.stream().map(attr -> {
            ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
            valueEntity.setAttrId(attr.getAttrId());
            AttrEntity byId = attrService.getById(attr.getAttrId());
            valueEntity.setAttrName(byId.getAttrName());
            valueEntity.setAttrValue(attr.getAttrValues());
            valueEntity.setSpuId(InfoEntity.getId());
            valueEntity.setQuickShow(attr.getShowDesc());
            return valueEntity;
        }).collect(Collectors.toList());
        productAttrValueService.saveProductAttr(collect);
        // 5. 保存spu的积分信息 ;gulimall_sms-》sms_spu_bounds

        // 6. 保存当前spu对应的所有sku信息 ;
        List<Skus> skus = vo.getSkus();
        if(skus != null && skus.size() > 0){
            skus.forEach(item -> {
                // 默认图片
                String defaultImg = "";
                List<Images> imagesList = item.getImages();
                for (Images image : imagesList) {
                    if(image.getDefaultImg() == 1){
                        defaultImg = image.getImgUrl();
                    }
                }
                // private String skuName;
                //    private BigDecimal price;
                //    private String skuTitle;
                //    private String skuSubtitle;
                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
                BeanUtils.copyProperties(item,skuInfoEntity);
                skuInfoEntity.setBrandId(InfoEntity.getBrandId());
                skuInfoEntity.setCatalogId(InfoEntity.getCatalogId());
                skuInfoEntity.setSkuDefaultImg(defaultImg);
                skuInfoEntity.setSaleCount(0L);
                skuInfoEntity.setSpuId(InfoEntity.getId());


                // 6.1 sku的基本信息 ;pms_sku_info
                skuInfoService.saveSkuInfo(skuInfoEntity);

                Long skuId = skuInfoEntity.getSkuId();

                List<SkuImagesEntity> imagesEntities = imagesList.stream().map(img -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setImgUrl(img.getImgUrl());
                    skuImagesEntity.setDefaultImg(img.getDefaultImg());
                    return skuImagesEntity;
                }).collect(Collectors.toList());

                // 6.2 sku的图片信息 ;pms_sku_images
                skuImagesService.saveBatch(imagesEntities);

                List<Attr> attr = item.getAttr();
                List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attr.stream().map(attr1 -> {
                    SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                    BeanUtils.copyProperties(attr1, skuSaleAttrValueEntity);
                    skuSaleAttrValueEntity.setSkuId(skuId);
                    return skuSaleAttrValueEntity;
                }).collect(Collectors.toList());
                // 6.3 sku的销售属性信息 ;pms_sku_sale_attr_value
                skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);

            });
        }
        // 6.4 sku的优惠、满减等信息 ;gulimall_sms-》sms_sku_ladder/sms_sku_full_reduction/sms_member_price
    }
}
public interface SkuInfoService extends IService<SkuInfoEntity> {

    PageUtils queryPage(Map<String, Object> params);

    //保存 sku 基本信息
    void saveSkuInfo(SkuInfoEntity skuInfoEntity);
}

8. 调用远程服务保存优惠等相关信息

首先我们是使用gulimall-product 调用gulimall-coupon 的保存积分信息和优惠满减信息。

1. 在common 模块中放入 vo来存储对应数据


同时product项目开始扫描FeignClient功能 

@Data
public class SpuBoundsTo {
    private  Long spuId;

    private BigDecimal buyBounds;

    private BigDecimal growBounds;

}
@Data
public class SkuReductionTo {

    private Long skuId;
    private int fullCount;
    private BigDecimal discount;
    private int countStatus;
    private BigDecimal fullPrice;
    private BigDecimal reducePrice;
    private int priceStatus;
    private List<MemberPrice> memberPrice;
}
@Data
public class MemberPrice {
    private Long id;
    private String name;
    private BigDecimal price;
}

@EnableFeignClients(basePackages = "com.atguigu.gulimall.product.feign")
@EnableDiscoveryClient
@MapperScan("com.atguigu.gulimall.product.dao")
@SpringBootApplication
public class GulimallProductApplication {

	public static void main(String[] args) {
		SpringApplication.run(GulimallProductApplication.class, args);
	}

}

 2, gulimall-product 模块引入 @FeignClient 注解,开启远程调用功能。调用gulimall-coupon

@FeignClient("gulimall-coupon")
public interface CouponFeignService {

    /**
     * CouponFeignService.saveSpuBounds(spuBoundsTo)
     * 1)、@RequestBody 将这个对象转为json.
     * 2)、找到gulimall-coupon服务,给/coupon/spubounds/save发请求。
     *      将上一步转的json放在请求体位置,发送请求;
     * 3)、对方服务接收到请求。请求体里有json数据。
     *      (@RequestBody SpuBoundsEntity spuBounds)将请求体的json转为SpuBoundsEntity;
     * 注意:只要json数据模型兼容(一致)。双方服务无需使用同一个实体。
     *      方法名无需一致。
     *
     * @param spuBoundsTo
     * @return
     */
    @PostMapping("/coupon/spubounds/save")
    public R saveSpuBounds(@RequestBody SpuBoundsTo spuBoundsTo);

    @PostMapping("/coupon/skufullreduction/saveInfo")
    public R saveSkuReduction(@RequestBody SkuReductionTo skuReductionTo);
    
}

/**
     * CouponFeignService.saveSpuBounds(spuBoundsTo)
     * 1)、@RequestBody 将这个对象转为json.
     * 2)、找到gulimall-coupon服务,给/coupon/spubounds/save发请求。
     *      将上一步转的json放在请求体位置,发送请求;
     * 3)、对方服务接收到请求。请求体里有json数据。
     *      (@RequestBody SpuBoundsEntity spuBounds)将请求体的json转为SpuBoundsEntity;
     * 注意:只要json数据模型兼容(一致)。双方服务无需使用同一个实体。
     *      方法名无需一致。
     *
     * @param spuBoundsTo
     * @return

保存积分信息  对应gulimall-coupon 中的SpuBoundsController 的 save 方法

/**
 * 商品spu积分设置
 *
 * @author liyang
 * @email [email protected]
 * @date 2023-08-07 14:47:12
 */
@RestController
@RequestMapping("coupon/spubounds")
public class SpuBoundsController {

    @Autowired
    private SpuBoundsService spuBoundsService;

    /**
     * 保存
     */
    @PostMapping("/save")
    public R save(@RequestBody SpuBoundsEntity spuBounds){
		spuBoundsService.save(spuBounds);

        return R.ok();
    }
}

 满减优惠


/**
 * 商品满减信息
 *
 * @author liyang
 * @email [email protected]
 * @date 2023-08-07 14:47:13
 */
@RestController
@RequestMapping("coupon/skufullreduction")
public class SkuFullReductionController {

    @Autowired
    private SkuFullReductionService skuFullReductionService;

    /**
     * 保存商品满减信息, 由gulimall-product 进行远程调用,保存 sku 信息
     */
    @PostMapping("/saveInfo")
    //@RequiresPermissions("coupon:skufullreduction:list")
    public R saveInfo(@RequestBody SkuReductionTo skuReductionTo){
        skuFullReductionService.saveSkuReduction(skuReductionTo);

        return R.ok();
    }

}
public interface SkuFullReductionService extends IService<SkuFullReductionEntity> {
 
    PageUtils queryPage(Map<String, Object> params);
 
    void saveSkuReduction(SkuReductionTo skuReductionTo);
}
@Service("skuFullReductionService")
public class SkuFullReductionServiceImpl extends ServiceImpl<SkuFullReductionDao, SkuFullReductionEntity> implements SkuFullReductionService {
 
    @Resource
    private SkuLadderService skuLadderService;
    @Resource
    private MemberPriceService memberPriceService;
 
    ...
 
    @Override
    public void saveSkuReduction(SkuReductionTo skuReductionTo) {
        // sku的优惠、满减等信息 ;gulimall_sms-》sms_sku_ladder/sms_sku_full_reduction/sms_member_price
        // 1. sms_sku_ladder
        SkuLadderEntity skuLadderEntity = new SkuLadderEntity();
        BeanUtils.copyProperties(skuReductionTo,skuLadderEntity);
        skuLadderEntity.setAddOther(skuReductionTo.getCountStatus());
        // 折后价price
        skuLadderService.save(skuLadderEntity);
 
        // 2. sms_sku_full_reduction
        SkuFullReductionEntity skuFullReductionEntity = new SkuFullReductionEntity();
        BeanUtils.copyProperties(skuReductionTo,skuFullReductionEntity);
        skuFullReductionEntity.setAddOther(skuReductionTo.getPriceStatus());
        this.save(skuFullReductionEntity);
 
        // 3. sms_member_price
        List<MemberPrice> memberPrice = skuReductionTo.getMemberPrice();
        List<MemberPriceEntity> collect = memberPrice.stream().map(item -> {
            MemberPriceEntity memberPriceEntity = new MemberPriceEntity();
            memberPriceEntity.setSkuId(skuReductionTo.getSkuId());
            memberPriceEntity.setMemberLevelId(item.getId());
            memberPriceEntity.setMemberLevelName(item.getName());
            memberPriceEntity.setMemberPrice(item.getPrice());
            memberPriceEntity.setAddOther(1);
            return memberPriceEntity;
        }).collect(Collectors.toList());
        memberPriceService.saveBatch(collect);
 
    }
 
}
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {
    @Resource
    private SpuInfoDescService spuInfoDescService;
    @Resource
    private SpuImagesService spuImagesService;
    @Resource
    private AttrService attrService;
    @Resource
    private ProductAttrValueService productAttrValueService;
    @Resource
    private SkuInfoService skuInfoService;
    @Resource
    private SkuImagesService skuImagesService;
    @Resource
    private SkuSaleAttrValueService skuSaleAttrValueService;
    @Resource
    private CouponFeignService couponFeignService;
 
    ...
 
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSpuInfo(SpuSaveVo vo) {
        // 1. 保存spu的基本信息 ;pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        BeanUtils.copyProperties(vo,spuInfoEntity);
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
        this.saveBaseSpuInfo(spuInfoEntity);
        // 2. 保存spu的描述图片 ;pms_spu_info_desc
        List<String> decript = vo.getDecript();
        SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
        descEntity.setSpuId(spuInfoEntity.getId());
        descEntity.setDecript(String.join(",",decript));
        spuInfoDescService.saveSpuInfoDesc(descEntity);
 
        // 3. 保存spu的图片集 ;pms_spu_images
        List<String> images = vo.getImages();
        spuImagesService.saveImages(spuInfoEntity.getId(),images);
        // 4. 保存spu的规格参数 ;pms_product_attr_value
        List<BaseAttrs> baseAttrs = vo.getBaseAttrs();
        List<ProductAttrValueEntity> collect = baseAttrs.stream().map(attr -> {
            ProductAttrValueEntity valueEntity = new ProductAttrValueEntity();
            valueEntity.setAttrId(attr.getAttrId());
            AttrEntity byId = attrService.getById(attr.getAttrId());
            valueEntity.setAttrName(byId.getAttrName());
            valueEntity.setAttrValue(attr.getAttrValues());
            valueEntity.setSpuId(spuInfoEntity.getId());
            valueEntity.setQuickShow(attr.getShowDesc());
            return valueEntity;
        }).collect(Collectors.toList());
        productAttrValueService.saveProductAttr(collect);
        // 5. 保存spu的积分信息 ;gulimall_sms-》sms_spu_bounds
        Bounds bounds = vo.getBounds();
        SpuBoundsTo spuBoundsTo = new SpuBoundsTo();
        BeanUtils.copyProperties(bounds,spuBoundsTo);
        spuBoundsTo.setSpuId(spuInfoEntity.getId());
        R r = couponFeignService.saveSpuBounds(spuBoundsTo);
        if(r.getCode() != 0){
            log.error("远程保存spu积分信息失败");
        }
 
        // 6. 保存当前spu对应的所有sku信息 ;
        List<Skus> skus = vo.getSkus();
        if(skus != null && skus.size() > 0){
            skus.forEach(item -> {
                // 默认图片
                String defaultImg = "";
                List<Images> imagesList = item.getImages();
                for (Images image : imagesList) {
                    if(image.getDefaultImg() == 1){
                        defaultImg = image.getImgUrl();
                    }
                }
                // private String skuName;
                //    private BigDecimal price;
                //    private String skuTitle;
                //    private String skuSubtitle;
                SkuInfoEntity skuInfoEntity = new SkuInfoEntity();
                BeanUtils.copyProperties(item,skuInfoEntity);
                skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
                skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
                skuInfoEntity.setSkuDefaultImg(defaultImg);
                skuInfoEntity.setSaleCount(0L);
                skuInfoEntity.setSpuId(spuInfoEntity.getId());
                // 6.1 sku的基本信息 ;pms_sku_info
                skuInfoService.saveSkuInfo(skuInfoEntity);
 
                Long skuId = skuInfoEntity.getSkuId();
 
                List<SkuImagesEntity> imagesEntities = imagesList.stream().map(img -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuId);
                    skuImagesEntity.setImgUrl(img.getImgUrl());
                    skuImagesEntity.setDefaultImg(img.getDefaultImg());
                    return skuImagesEntity;
                }).collect(Collectors.toList());
 
                // 6.2 sku的图片信息 ;pms_sku_images
                skuImagesService.saveBatch(imagesEntities);
 
                List<Attr> attr = item.getAttr();
                List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attr.stream().map(attr1 -> {
                    SkuSaleAttrValueEntity skuSaleAttrValueEntity = new SkuSaleAttrValueEntity();
                    BeanUtils.copyProperties(attr1, skuSaleAttrValueEntity);
                    skuSaleAttrValueEntity.setSkuId(skuId);
                    return skuSaleAttrValueEntity;
                }).collect(Collectors.toList());
                // 6.3 sku的销售属性信息 ;pms_sku_sale_attr_value
                skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);
 
                // 6.4 sku的优惠、满减等信息 ;gulimall_sms-》sms_sku_ladder/sms_sku_full_reduction/sms_member_price
                SkuReductionTo skuReductionTo = new SkuReductionTo();
                BeanUtils.copyProperties(item,skuReductionTo);
                skuReductionTo.setSkuId(skuId);
                R r1 = couponFeignService.saveSkuReduction(skuReductionTo);
                if(r1.getCode() != 0){
                    log.error("远程保存sku优惠信息失败");
                }
 
            });
        }
    }
 
    @Override
    public void saveBaseSpuInfo(SpuInfoEntity spuInfoEntity) {
        this.baseMapper.insert(spuInfoEntity);
    }
 
}

 9. 商品保存debug 完成

10. SPU 检索

当我们进入spu管理界面

会出现spu基本信息列表,当我们在搜索框输入相关信息是,希望能检索到相关信息

我们应该在SpuInfoController 中进行更改方法,使其能够进行搜索功能

SpuInfoController

 /**
     * spu管理页面列表
     */
    @RequestMapping("/list")
    public R list(@RequestParam Map<String, Object> params){

//        PageUtils page = spuInfoService.queryPage(params);
        PageUtils page = spuInfoService.queryPageCondition(params);

        return R.ok().put("page", page);
    }
@Service("SpuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {
    @Resource
    private SpuInfoDescService spuInfoDescService;
    @Resource
    private SpuImagesService spuImagesService;
    @Resource
    private AttrService attrService;
    @Resource
    private ProductAttrValueService productAttrValueService;
    @Resource
    private SkuInfoService skuInfoService;
    @Resource
    private SkuImagesService skuImagesService;
    @Resource
    private SkuSaleAttrValueService skuSaleAttrValueService;
    @Resource
    private CouponFeignService couponFeignService;

    //spu 管理页面列表数据,同时加载搜索框功能
    @Override
    public PageUtils queryPageCondition(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();
        /**
         * status:
         * 0
         * key:
         * brandId:
         * 7
         * catelogId:
         * 225
         */
        String key = (String) params.get("key");
        if(!StringUtils.isEmpty(key)){
            // 或两边的条件要括起来使用and()
            wrapper.and((w) -> {
                w.eq("id",key).or().like("spu_name",key);
            });
        }
        String status = (String) params.get("status");
        if(!StringUtils.isEmpty(status)){            //商品信息状态要与顶部状态栏一致
            wrapper.eq("publish_status",status);
        }
        String brandId = (String) params.get("brandId");   //品牌Id
        if(!StringUtils.isEmpty(brandId) && !"0".equals(brandId)){
            wrapper.eq("brand_id",brandId);
        }
        String catelogId = (String)params.get("catelogId");
        if(!StringUtils.isEmpty(catelogId) && !"0".equals(catelogId)){
            wrapper.eq("catalog_id",catelogId);
        }
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                wrapper
        );
        return new PageUtils(page);
    }
}

在application.yml 中添加配置,用来返回固定的日期格式

spring:
  datasource:
    username: root
    password: abc123
    url: jdbc:mysql://192.168.56.105:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    alicloud:
      access-key: LTAI5t68jUrcr46DeeeLjGDV
      secret-key: SXwnCFGCmm0NbENoD2uPWg0xxAIdj5
      oss:
        endpoint: oss-cn-beijing.aliyuncs.com


  jackson:    #在spu检索中进行配置日期,返回格式要固定
    date-format: yyyy-MM-dd HH:mm:ss

11. SKU 检索

@RestController
@RequestMapping("product/skuinfo")
public class SkuInfoController {
    @Autowired
    private SkuInfoService skuInfoService;

    @Autowired
    private SpuInfoService spuInfoService;

    /**
     * 列表
     */
    @RequestMapping("/list")
    public R list(@RequestParam Map<String, Object> params){
//        PageUtils page = skuInfoService.queryPage(params);
        PageUtils page = skuInfoService.queryPageCondition(params);

        return R.ok().put("page", page);
    }
}
public interface SkuInfoService extends IService<SkuInfoEntity> {

    PageUtils queryPage(Map<String, Object> params);

    //保存 sku 基本信息
    void saveSkuInfo(SkuInfoEntity skuInfoEntity);

    //Sku管理页面查询数据,添加搜索框功能
    PageUtils queryPageCondition(Map<String, Object> params);
}

@Service("skuInfoService")
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoDao, SkuInfoEntity> implements SkuInfoService {


    //Sku 管理页面基本信息,添加搜索框功能
    @Override
    public PageUtils queryPageCondition(Map<String, Object> params) {
        /**
         * key:
         * catelogId:
         * 0
         * brandId:
         * 0
         * min:
         * 0
         * max:
         * 0
         */
        QueryWrapper<SkuInfoEntity> wrapper = new QueryWrapper<>();
        String key = (String) params.get("key");
        if(!StringUtils.isEmpty(key)){
            // 或两边的条件要括起来使用and()
            wrapper.and((w) -> {
                w.eq("sku_id",key).or().like("sku_name",key);
            });
        }
        String brandId = (String) params.get("brandId");
        if(!StringUtils.isEmpty(brandId) && !"0".equals(brandId)){
            wrapper.eq("brand_id",brandId);
        }
        String catelogId = (String)params.get("catelogId");
        if(!StringUtils.isEmpty(catelogId) && !"0".equals(catelogId)){
            wrapper.eq("catalog_id",catelogId);
        }
        String min = (String) params.get("min");
        if(!StringUtils.isEmpty(min)){
            wrapper.ge("price",min);
        }

        //添加检索价格区间
        String max = (String) params.get("max");
        if(!StringUtils.isEmpty(max)){
            try {
                BigDecimal bigDecimal = new BigDecimal(max);
                if(bigDecimal.compareTo(new BigDecimal("0")) == 1) {
                    wrapper.le("price", max);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        IPage<SkuInfoEntity> page = this.page(
                new Query<SkuInfoEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_55347789/article/details/132870200