目录
一、需求描述
商品的规格参数属于品牌下的各个属性分组中,它与之前的创建的属性分组相关联。
属性分组用于管理商品的的各个属性:比如手机中有主题,基本信息等分组属性。
规格参数表示在上面主题,基本信息属性分组下的商品规格参数。
而销售属性与属性分组没有连接,属于商品的单独部分
总而言之 : 商品(属性分组(规格参数)) 一 对 多关系
商品(销售属性):属性分组与销售属性是同一层级
但他们共用一张表,因为值都相同
1、数据表
attr:规格参数表
attr-attrgoup-relation:规格参数与属性分组的关联表(销售属性与之不关联)
attr_type 用于区分规格参数和销售属性
2、需要完善的接口
1.获取分类规格参数:/product/attr/base/list/{catelogId}
2.保存属性【规格参数,销售属性】:/product/attr/save
3.查询属性详情:/product/attr/info/{attrId}
4.修改属性:/product/attr/update
5.获取分类销售属性:/product/attr/sale/list/{catelogId}
6.获取属性分组的关联的所有属性:/product/attrgroup/{attrgroupId}/attr/relation
7.添加属性与分组关联关系:/product/attrgroup/attr/relation
8.删除属性与分组的关联关系:/product/attrgroup/attr/relation/delete
二、前置工作
1、VO类
product下创建VO
AttrRespVo 用于回显属性属于哪个分组对应的分组名字
package com.atguigu.gulimall.product.vo;
import lombok.Data;
@Data
public class AttrRespVo extends AttrVo{
/**
* "catelogName": "手机/数码/手机", //所属分类名字
* "groupName": "主体", //所属分组名字
*
*/
private String catelogName;
private String groupName;
private Long[] catelogPath;
}
AttrVo 基本VO与AttrEntity相同:多一个attrGroupId属性
package com.atguigu.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;
}
AttrGroupRelationVo 用于属性与分组连接对应的id
package com.atguigu.gulimall.product.vo;
import lombok.Data;
@Data
public class AttrGroupRelationVo {
private Long attrId;
private Long attrGroupId;
}
2、固定值枚举类
在common下创建constant用于固定值的枚举
package com.atguigu.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;
}
}
}
三、获取分类【规格参数 + 销售属性】
前端接口:/product/attr/base/list/{catelogId} + /product/attr/sale/list/{catelogId}
本来是两个接口 但是由于是一张表,增删改查可以做成一个功能
1、controller类
创建分类查询方法queryBaseAttrPage
@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);
}
2、service类
PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId, String type);
3、Impl类
@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.hasLength(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);
// 1. 设置分类和分组的名字
if("base".equalsIgnoreCase(type)){
AttrAttrgroupRelationEntity attrId = relationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getAttrId()));
if(attrId != 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;
}
4、测试
四、新增保存【规格参数 + 销售属性】
前端接口 :/product/attr/save
1、controller类
@RequestMapping("/save")
//@RequiresPermissions("product:attr:save")
public R save(@RequestBody AttrVo attr){
attrService.saveAttr(attr);
return R.ok();
}
2、service类
void saveAttr(AttrVo attr);
3、Impl类
@Override
public void saveAttr(AttrVo attr) {
AttrEntity attrEntity = new AttrEntity();
BeanUtils.copyProperties(attr,attrEntity);
// 1.保存基本数据
this.save(attrEntity);
// 2.保存关联关系
if(attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()){
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
relationEntity.setAttrGroupId(attr.getAttrGroupId());
relationEntity.setAttrId(attrEntity.getAttrId());
relationDao.insert(relationEntity);
}
}
4、测试
五、查询【规格参数 + 销售属性】
查询重要用于当点击修改时:回显当前已经存在的数据
前端接口 :/product/attr/info/{attrId}
1、controller类
@RequestMapping("/info/{attrId}")
//@RequiresPermissions("product:attr:info")
public R info(@PathVariable("attrId") Long attrId){
AttrRespVo respVo = attrService.getAttrInfo(attrId);
return R.ok().put("attr", respVo);
}
2、service类
AttrRespVo getAttrInfo(Long attrId);
3、Impl类
@Override
public AttrRespVo getAttrInfo(Long attrId) {
AttrRespVo respVo = new AttrRespVo();
AttrEntity attrEntity = this.getById(attrId);
BeanUtils.copyProperties(attrEntity,respVo);
// 1.设置分组信息
if(attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()){
AttrAttrgroupRelationEntity attrgroupRelation = relationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id",attrId));
if(attrgroupRelation != null){
respVo.setAttrGroupId(attrgroupRelation.getAttrGroupId());
AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrgroupRelation.getAttrGroupId());
if(attrEntity != 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;
}
六、修改【规格参数 + 销售属性】
前端接口 :/product/attr/update
1、controller类
/**
* 修改
*/
@RequestMapping("/update")
//@RequiresPermissions("product:attr:update")
public R update(@RequestBody AttrVo attr){
attrService.updateAttr(attr);
return R.ok();
}
2、service类
void updateAttr(AttrVo attr);
3、Impl类
@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);
}
}
}
4、测试
七、获取属性分组的关联的所有属性
前端接口:/product/attrgroup/{attrgroupId}/attr/relation
这里功能主要与属性分组有关
1、controller类
这里功能主要与属性分组有关,所以controller类回到AttrGroupContoller编写
@GetMapping("/{attrgroupId}/attr/relation")
public R attrRelation(@PathVariable("attrgroupId") Long attrgroupId){
List<AttrEntity> entities = attrService.getRelationAttr(attrgroupId);
return R.ok().put("data", entities);
}
2、service类
但是这里还是调用的attrService中的方法,因为回显的数据还是属于规格参数表
List<AttrEntity> getRelationAttr(Long attrgroupId);
3、Impl类
// 根据分子id显示属性关联信息
@Override
public List<AttrEntity> getRelationAttr(Long attrgroupId) {
List<AttrAttrgroupRelationEntity> entities = relationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id",attrgroupId));
List<Long> attrIds = entities.stream().map((attr) -> {
return attr.getAttrId();
}).collect(Collectors.toList());
if(attrIds == null || attrIds.size() == 0){
return null;
}
Collection<AttrEntity> attrEntities = this.listByIds(attrIds);
return (List<AttrEntity>) attrEntities;
}
4、测试
上市年份绑定在主题分类下
回到属性分组界面,点击主题的关联
八、添加属性与分组关联关系
前端接口:/product/attrgroup/attr/relation
1、controller类
@PostMapping("/attr/relation")
public R addRelation(@RequestBody List<AttrGroupRelationVo> vos){
relationService.saveBatch(vos);
return R.ok();
}
2、service类
这里调用的是AttrAttrgroupRelationService relationService;中的方法
3、Impl类
@Override
public void saveBatch(List<AttrGroupRelationVo> vos) {
List<AttrAttrgroupRelationEntity> collect = vos.stream().map(item -> {
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
BeanUtils.copyProperties(item, relationEntity);
return relationEntity;
}).collect(Collectors.toList());
this.saveBatch(collect);
}
4、测试
与下面获取属性分组没有关联一起测试
九、删除属性与分组的关联关系
前端接口:/product/attrgroup/attr/relation/delete
1、controller类
@PostMapping("/attr/relation/delete")
public R deleteRelation(@RequestBody AttrGroupRelationVo[] vos){
attrService.deleteRelation(vos);
return R.ok();
}
2、service类
void deleteRelation(AttrGroupRelationVo[] vos);
3、Impl类
@Override
public void deleteRelation(AttrGroupRelationVo[] vos) {
// relationDao.delete(new QueryWrapper<>().eq("attr_id", 1L).eq("attr_group_id", 1L));
List<AttrAttrgroupRelationEntity> entities = Arrays.asList(vos).stream().map((item) -> {
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
BeanUtils.copyProperties(item, relationEntity);
return relationEntity;
}).collect(Collectors.toList());
relationDao.deleteBatchRelation(entities);
}
4、测试
点击删除后
数据库也为空
十、获取属性分组没有关联的其他属性
前端接口:/product/attrgroup/{attrgroupId}/noattr/relation
1、controller类
@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);
}
2、service类
PageUtils getNoRelationAttr(Map<String, Object> params, Long attrgroupId);
3、Impl类
// 获取当前分组没有关联的所以属性
@Override
public PageUtils getNoRelationAttr(Map<String, Object> params, Long attrgroupId) {
// 1.当前分组只能关联自己所属的分类里面的所有属性
AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrgroupId);
Long catelogId = attrGroupEntity.getCatelogId();
// 2 当前分组只能关联别的分组没有引用的属性
// 2.1)当前分类下的其他分组
List<AttrGroupEntity> group = attrGroupDao.selectList(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId));
List<Long> collect = group.stream().map(item -> {
return item.getAttrGroupId();
}).collect(Collectors.toList());
//2.2)这些分组关联的属性
List<AttrAttrgroupRelationEntity> groupId = relationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().in("attr_group_id", collect));
List<Long> attrIds = groupId.stream().map(item -> {
return item.getAttrId();
}).collect(Collectors.toList());
//2.3)当前分类所有的属性中移除这些属性
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.hasLength(key)){
wrapper.and((w)->{
w.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;
}
4、测试
点击新建关联 可以看到没用关联的规格参数
添加入网型号到主体
再点新增时显示为关联的规格参数