9.商品服务-平台属性
介绍:
规格参数即:基本属性--有关联关系,需要属性分组
销售属性:销售属性-没有关联关系,不需要属性分组
1.规格参数新增与vo
在查询全部的时候如果带了key值,我们也应该把key带上模糊查询
修改queryPage方法
//分页查询,需要匹配key的模糊查询 @Override public PageUtils queryPage(Map<String, Object> params, Long catlogId) { String key= (String) params.get("key"); 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(catlogId==0){ IPage<AttrGroupEntity> page = this.page(new Query<AttrGroupEntity>().getPage(params), wrapper); return new PageUtils(page); }else{ wrapper.eq("catelog_id",catlogId);//有id的时候才判断是否相等 IPage<AttrGroupEntity> page = this.page(new Query<AttrGroupEntity>().getPage(params), wrapper); return new PageUtils(page); } }
2.vo值对象:用于业务层之间的数据传递,用new关键字创建,由gc回收
在这里其实也可以叫view Object:视图对象,之前我们在实体类上添加了很多注解:例如JsonInclude,TableField这样的操作是不规范的
vo以后的作用就是:1.接收页面传递来的数据,封装对象 2.将业务处理完成的对象,封装成页面需要使用的工具
不需要任何与数据库相关的注解
Request URL: http://localhost:88/api/product/attr/save,现在的情况是,它在保存的时候,只是保存了attr,并没有保存attrgroup,为了解决这个问题,我们新建了一个vo/AttrVo.java
@Data public class AttrVo implements Serializable { private static final long serialVersionUID = 1L; /** * 属性id */ private Long attrId; /** * 属性名 */ private String attrName; /** * 是否需要检索[0-不需要,1-需要] */ private Integer searchType; /** * 属性图标 */ private String icon; /** * 可选值列表[用逗号分隔] */ private String valueSelect; /** * 属性类型[0-销售属性,1-基本属性 */ private Integer attrType; /** * 启用状态[0 - 禁用,1 - 启用] */ private Long enable; /** * 所属分类 */ private Long catelogId; /** * 快速展示【是否展示在介绍上;0-否 1-是】,在sku中仍然可以调整 */ private Integer showDesc; //分组的id private Long attrGroupId; }
3.修改attrController的save方法
改为使用Vo对象
@RequestMapping("/save") //@RequiresPermissions("product:attr:save") public R save(@RequestBody AttrVo attr){ attrService.saveAttr(attr); return R.ok(); }
实现的方法
@Override @Transactional//事务原子性 public void saveAttr(AttrVo attr) { AttrEntity attrEntity = new AttrEntity();//这是一个po持久对象用于保存数据库信息 BeanUtils.copyProperties(attr,attrEntity);//使用BeanUtils拷贝属性,两者属性名必须一一对应 this.save(attrEntity);//保存基本数据 //保存关联关系 AttrAttrgroupRelationEntity entity = new AttrAttrgroupRelationEntity(); entity.setAttrGroupId(attr.getAttrGroupId()); entity.setAttrId(attrEntity.getAttrId()); relationService.save(entity);//最好是注入service }
这样在保存规格参数的时候就可以关联表一起保存了
4.规格参数列表
@GetMapping("/base/list/{catelogId}") //@RequiresPermissions("product:attr:list") public R baseAttrList(@RequestParam Map<String, Object> params, @PathVariable("catelogId") Long catelogId){ PageUtils page = attrService.queryBaseAttrPage(params,catelogId); return R.ok().put("page", page); }
@Override public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId) { QueryWrapper<AttrEntity> wrapper = new QueryWrapper<>(); if(catelogId!=0){//不为0=存在,就添加eq条件 wrapper.eq("catelog_Id",catelogId); } //由于上面有可能添加了eq所以我们下面要使用and String key= (String) params.get("key"); if(!StringUtils.isEmpty(key)){ wrapper.and((qwrapper)->{ qwrapper.eq("attr_id",key).or().like("attr_name",key); }); } IPage<AttrEntity> page = this.page(new Query<AttrEntity>().getPage(params), wrapper);//得到分页 return new PageUtils(page); }
可以看到已经查询出来了,但是还有两个字段是空的
从接口文档中也可以看到,需要这两个参数 catelogName和groupName
自定义封装一个Vo,其实不建议用继承
@Data public class AttrRespVo extends AttrVo implements Serializable { private String catelogName;//分类名字 private String groupName;//所属分组 }
逻辑分析:
要查询这两个属性,我们目前有的东西:catelogId
那么我们就可以之间拿到catelog的service直接进行查询
需要获取groupName,我们首先得有groupId
groupId在AttrAttrgroupRelation这张表中有attr_id和group_id的对应关系
于是乎我们通过attr_id相等这一条件,查询到AttrAttrgroupRelation的group_id,再获取名字
@Autowired AttrAttrgroupRelationService relationService;//最好是注入service @Autowired AttrGroupService attrGroupService; @Autowired CategoryService categoryService; @Override public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId) { QueryWrapper<AttrEntity> wrapper = new QueryWrapper<>(); if(catelogId!=0){//不为0=存在,就添加eq条件 wrapper.eq("catelog_Id",catelogId); } //由于上面有可能添加了eq所以我们下面要使用and String key= (String) params.get("key"); if(!StringUtils.isEmpty(key)){ wrapper.and((qwrapper)->{ qwrapper.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> attrEntities=page.getRecords(); List<AttrRespVo> collect = attrEntities.stream().map((attrEntity) -> { AttrRespVo attrRespVo = new AttrRespVo(); BeanUtils.copyProperties(attrEntity, attrRespVo);//拷贝属性 //获得当前关联的对象 AttrAttrgroupRelationEntity attrId = relationService.getOne(new QueryWrapper<AttrAttrgroupRelationEntity>() .eq("attr_id", attrEntity.getAttrId()));//通过属性id相等查到关联对象 if (attrId != null) {//分组关联信息有可能是空的 //分组 AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrId.getAttrGroupId()); attrRespVo.setCatelogName(attrGroupEntity.getAttrGroupName()); } //分类 CategoryEntity categoryEntity = categoryService.getById(attrEntity.getCatelogId()); if (categoryEntity != null) { attrRespVo.setGroupName(categoryEntity.getName()); } return attrRespVo; }).collect(Collectors.toList()); pageUtils.setList(collect); return pageUtils; }
可以看到模糊查询,分类分组都有了
5.平台属性规格参数修改的时候回显列表
需要两个格外的属性一个是path一个是groupid
@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); }
@Override public AttrRespVo getAttrInfo(Long attrId) { //需要额外携带的东西:attrgroup_id和catelogPath AttrEntity attrEntity = this.getById(attrId); AttrRespVo respVo = new AttrRespVo(); BeanUtils.copyProperties(attrEntity, respVo); //获取分组的id AttrAttrgroupRelationEntity one = relationService.getOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId)); if (one != null) { Long attrGroupId = one.getAttrGroupId(); respVo.setAttrGroupId(attrGroupId); //把名字也顺便带进去 AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrGroupId); if(attrGroupEntity!=null){ respVo.setGroupName(attrGroupEntity.getAttrGroupName()); } } //获取分类的路径,这个在之前的项目里做过,所以直接调用接口 Long[] catelogPath = categoryService.findCatelogPath(attrEntity.getCatelogId()); respVo.setCatelogPath(catelogPath); //同样也可以设置分类的名字 CategoryEntity categoryEntity = categoryService.getById(attrEntity.getCatelogId()); if(categoryEntity!=null)//每次查询之后都得判断 respVo.setCatelogName(categoryEntity.getName()); return respVo; }
6.修改更新时的关联属性
在修改点击确定后,所属分类也会跟着修改了
@RequestMapping("/update") //@RequiresPermissions("product:attr:update") public R update(@RequestBody AttrVo attr){//在修改点击确定的时候我们获得的是一个vo属性,因为不需要path,但是又需要级联更新attrgroup所以需要groupid attrService.updateDetail(attr); return R.ok(); }
@Transactional @Override public void updateDetail(AttrVo attr) { AttrEntity attrEntity = new AttrEntity(); BeanUtils.copyProperties(attr,attrEntity);//复制到数据库属性中 this.updateById(attrEntity);//更新 //修改分组的关联 AttrAttrgroupRelationEntity entity = new AttrAttrgroupRelationEntity(); entity.setAttrGroupId(attr.getAttrGroupId()); entity.setAttrId(attr.getAttrId()); //判断是否有这一条记录,如果一开始就没有这条记录的话就应该是增加操作 int count = relationService.count(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId())); if(count==0){ relationService.save(entity); }else{ //使用这个属性替换掉表里原有的关联属性 relationService.update(entity,new UpdateWrapper<AttrAttrgroupRelationEntity>().eq("attr_id",attr.getAttrId())); } }
7.维护销售属性
1.显示列表
因为销售属性和基本属性基本一致所以我们用同一个方法来写
@GetMapping("/{attrType}/list/{catelogId}") //@RequiresPermissions("product:attr:list") public R baseAttrList(@RequestParam Map<String, Object> params, @PathVariable("catelogId") Long catelogId,@PathVariable("attrType")String attrType){ PageUtils page = attrService.queryBaseAttrPage(params,catelogId,attrType); return R.ok().put("page", page); }
@Override public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId, String attrType) { //如果是基本类型,就让他查type为1的基本类型否则就查type为0的销售属性 QueryWrapper<AttrEntity> wrapper = new QueryWrapper<AttrEntity>().eq("attr_type", "base".equalsIgnoreCase(attrType) ? ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() : ProductConstant.AttrEnum.aTTR_TYPE_SALE.getCode()); if (catelogId != 0) {//不为0=存在,就添加eq条件 wrapper.eq("catelog_Id", catelogId); } //由于上面有可能添加了eq所以我们下面要使用and String key = (String) params.get("key"); if (!StringUtils.isEmpty(key)) { wrapper.and((qwrapper) -> { qwrapper.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> attrEntities = page.getRecords(); List<AttrRespVo> collect = attrEntities.stream().map((attrEntity) -> { AttrRespVo attrRespVo = new AttrRespVo(); BeanUtils.copyProperties(attrEntity, attrRespVo);//拷贝属性 //销售属性是没有attrGroup的 if ("base".equalsIgnoreCase(attrType)) { //获得当前关联的对象 AttrAttrgroupRelationEntity attrId = relationService.getOne(new QueryWrapper<AttrAttrgroupRelationEntity>() .eq("attr_id", attrEntity.getAttrId()));//通过属性id相等查到关联对象 if (attrId != null&&attrId.getAttrGroupId()!=null) {//分组关联信息有可能是空的,里面的id也有可能是空的 //分组 AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrId.getAttrGroupId()); attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName()); } } //分类 CategoryEntity categoryEntity = categoryService.getById(attrEntity.getCatelogId()); if (categoryEntity != null) { attrRespVo.setCatelogName(categoryEntity.getName()); } return attrRespVo; }).collect(Collectors.toList()); pageUtils.setList(collect); return pageUtils; }
在关联关系列表中,如果是销售属性,我们新增多给销售属性多添加一个字段,所以这一块也要判断
@Override @Transactional//事务原子性 public void saveAttr(AttrVo attr) { AttrEntity attrEntity = new AttrEntity();//这是一个po持久对象用于保存数据库信息 BeanUtils.copyProperties(attr, attrEntity);//使用BeanUtils拷贝属性,两者属性名必须一一对应 this.save(attrEntity);//保存基本数据 //保存关联关系,在是基本属性的时候才保存,销售属性是没有的 if(attr.getAttrType()== ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()&&attr.getAttrGroupId()!=null){//AttrGroupId不为空才保存 AttrAttrgroupRelationEntity entity = new AttrAttrgroupRelationEntity(); entity.setAttrGroupId(attr.getAttrGroupId()); entity.setAttrId(attrEntity.getAttrId()); relationService.save(entity);//最好是注入service } }
在获取信息的时候也是,如果是销售属性是没有关联信息的
@Override public AttrRespVo getAttrInfo(Long attrId) { //需要额外携带的东西:attrgroup_id和catelogPath AttrEntity attrEntity = this.getById(attrId); AttrRespVo respVo = new AttrRespVo(); BeanUtils.copyProperties(attrEntity, respVo); //获取分组的id,基本信息才需要分组的id if(attrEntity.getAttrType()==ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode())
{ AttrAttrgroupRelationEntity one = relationService.getOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrId)); if (one != null) { Long attrGroupId = one.getAttrGroupId(); respVo.setAttrGroupId(attrGroupId); //把名字也顺便带进去 AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrGroupId); if (attrGroupEntity != null) { respVo.setGroupName(attrGroupEntity.getAttrGroupName()); } } } //获取分类的路径,这个在之前的项目里做过,所以直接调用接口 Long[] catelogPath = categoryService.findCatelogPath(attrEntity.getCatelogId()); respVo.setCatelogPath(catelogPath); //同样也可以设置分类的名字 CategoryEntity categoryEntity = categoryService.getById(attrEntity.getCatelogId()); if (categoryEntity != null)//每次查询之后都得判断 respVo.setCatelogName(categoryEntity.getName()); return respVo; }
更新信息的时候也是
@Transactional @Override public void updateDetail(AttrVo attr) { AttrEntity attrEntity = new AttrEntity(); BeanUtils.copyProperties(attr, attrEntity);//复制到数据库属性中 this.updateById(attrEntity);//更新 if(attrEntity.getAttrType()==ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) { //修改分组的关联 AttrAttrgroupRelationEntity entity = new AttrAttrgroupRelationEntity(); entity.setAttrGroupId(attr.getAttrGroupId()); entity.setAttrId(attr.getAttrId()); //判断是否有这一条记录,如果一开始就没有这条记录的话就应该是增加操作 int count = relationService.count(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId())); if (count == 0) { relationService.save(entity); } else { //使用这个属性替换掉表里原有的关联属性 relationService.update(entity, new UpdateWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attr.getAttrId())); } } }
我们发现,我们经常需要判断是基础属性还是销售属性,于是乎我们在common模块中添加
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 void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } AttrEnum(int code, String msg) { this.code = code; this.msg = msg; } } }
这样做的好处是,以后数据库修改规则了,我们只需要修改枚举类型就可以了
判断的时候如此判断
测试:
在销售属性中添加一个数据,attr成功添加数据,但是attrattrgroupreleation表并不新增数据
8.编写属性分组的关联功能
返回的数据就是我们当前分组里关联到的所有基本信息(规格参数)
@GetMapping("/{attrgroupId}/attr/relation") public R attrRelation(@PathVariable("attrgroupId") Long attrGroupId){ List<AttrEntity> entities= attrService.getRelationAttr(attrGroupId); return R.ok().put("data",entities); }
@Override public List<AttrEntity> getRelationAttr(Long attrGroupId) { List<AttrAttrgroupRelationEntity> entities = relationService.list(new QueryWrapper<AttrAttrgroupRelationEntity>() .eq("attr_group_id", attrGroupId)); //我们只需要属性id就行了 List<Long> list = entities.stream().map((attr) -> { return attr.getAttrId(); }).collect(Collectors.toList()); //根据id集合查出所有属性信息 if(list==null||list.size()==0){ return null; } List<AttrEntity> res = this.listByIds(list); return res; }
此时列表就显示出来了
9.编写批量删除功能
添加Vo
@Data public class AttrGroupRelationVo { private Long attrId; private Long attrGroupId; }
编写Controller
/** * 关联删除 */ @PostMapping("/attr/relation/delete") public R deleteRelation(@RequestBody AttrGroupRelationVo[] vos){//post请求有数据提交必须加上注解RequestBody attrService.deleteRelation(vos); return R.ok(); }
@Autowired AttrAttrgroupRelationDao relationDao; @Override public void deleteRelation(AttrGroupRelationVo[] vos) { //我们希望只发一次删除请求完成批量删除而不是用relationService.remove(new QueryWrapper<>().eq()) List<AttrAttrgroupRelationEntity> collect = Arrays.asList(vos).stream().map((item) -> { AttrAttrgroupRelationEntity entity = new AttrAttrgroupRelationEntity(); BeanUtils.copyProperties(item, entity); return entity; }).collect(Collectors.toList()); relationDao.deleteBatchRelation(collect); } }
标注一个自定义属性方便来写sql
@Mapper public interface AttrAttrgroupRelationDao extends BaseMapper<AttrAttrgroupRelationEntity> { void deleteBatchRelation(@Param("collect") List<AttrAttrgroupRelationEntity> collect); }
需要注意的是or一定要加上前后空格
<delete id="deleteBatchRelation"> delete from pms_attr_attrgroup_relation where <foreach collection="collect" item="item" separator=" OR "> (attr_id=#{item.attrId} and attr_group_id=#{item.attrGroupId}) </foreach> </delete>
10.编写新建关联中显示列表的功能
当前分组能关联的肯定是本分类下的,而且还不能被其他分组所关联
@RequestBody获取的信息在请求体中,@RequestParm获取的信息在请求头中
/** * 新增关联列表显示 */ @GetMapping("/{attrgroupId}/attr/relation") public R attrNoRelation(@RequestParam Map<String, Object> params,@PathVariable("attrgroupId") Long attrGroupId){ PageUtils page= attrService.getNoRelationAttr(params,attrGroupId); return R.ok().put("data",page); }
@Override public PageUtils getNoRelationAttr(Map<String, Object> params, Long attrGroupId) { //1.当前分组只能关联自己所属分类里面的所有属性 AttrGroupEntity attrGroupEntity = attrGroupService.getById(attrGroupId); Long catelogId = attrGroupEntity.getCatelogId(); //2.当前分组只能关联别的分组没有引用的属性 //2.1找到当前分类下的所有分组--》自己也要查,后续会连同自己的属性一起收集到collect里后进行剔除 List<AttrGroupEntity> attrGroupEntityList = attrGroupService.list(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId)); List<Long> collect = attrGroupEntityList.stream().map((item) -> { return item.getAttrGroupId();//我们只需要属性组id就行了 }).collect(Collectors.toList()); //2.2这些分组关联的属性-->获取所有attr_group_id字段与collect集合里一致的对象 List<AttrAttrgroupRelationEntity> relationEntities = relationService.list(new QueryWrapper<AttrAttrgroupRelationEntity>().in("attr_group_id", collect)); List<Long> collect1 = relationEntities.stream().map((item) -> { return item.getAttrId();//只需要属性id就可以了 }).collect(Collectors.toList()); //2.3从当前分类的所有属性中筛选掉这些属性,并且不查销售属性(销售属性没有关联关系) QueryWrapper<AttrEntity> attrEntityQueryWrapper = new QueryWrapper<AttrEntity>().eq("catelog_id", catelogId).eq("attr_type",ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()); if(collect1!=null&&collect1.size()>0){ attrEntityQueryWrapper.notIn("attr_id", collect1);//不为空并且大于0才进行判断 } //模糊查询 String key=(String) params.get("key"); if(!StringUtils.isEmpty(key)){ attrEntityQueryWrapper.and((w)->{ w.eq("attr_id",key).or().like("attr_name",key); }); } IPage<AttrEntity> page = this.page(new Query<AttrEntity>().getPage(params), attrEntityQueryWrapper); PageUtils pageUtils = new PageUtils(page); return pageUtils; }
11.新建关联中确认新增功能编写
/** * 新增关联新增功能 */ @PostMapping("/attr/relation") public R addRelation(@RequestBody List<AttrGroupRelationVo> vos){ attrAttrgroupRelationService.saveBatch(vos); return R.ok(); }
@Override public void saveBatch(List<AttrGroupRelationVo> vos) { //保存修改映射 List<AttrAttrgroupRelationEntity> collect = vos.stream().map(item -> { AttrAttrgroupRelationEntity entity = new AttrAttrgroupRelationEntity(); BeanUtils.copyProperties(item, entity); return entity; }).collect(Collectors.toList()); this.saveBatch(collect); }