一、完善品牌管理功能
1、分页信息有误:
后端的分页接口返回数据有问题,因为我们使用 mybatis-plus 要进行分页,需要引入分页插件:
https://mp.baomidou.com/guide/page.html
方法很简单,直接向容器中注入PaginationInterceptor即可:
package com.jiguiquan.zidanmall.product.config; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @EnableTransactionManagement @MapperScan("com.jiguiquan.zidanmall.product.dao") public class MybatisConfig { @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false paginationInterceptor.setOverflow(true); // 设置最大单页限制数量,默认 500 条,-1 不受限制 paginationInterceptor.setLimit(1000); // 开启 count 的 join 优化,只针对部分 left join paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); return paginationInterceptor; } }
然后重启服务,刷新页面就可以了,而且其他的页面也自动都完成了;
2、完善品牌查询时候的模糊查询功能
@Override public PageUtils queryPage(Map<String, Object> params) { //获取key String key = params.get("key").toString(); QueryWrapper<BrandEntity> wrapper = new QueryWrapper<>(); if (StringUtils.isNoneBlank(key)){ wrapper.and(obj -> obj.eq("brand_id", key).or().like("name", key)); } IPage<BrandEntity> page = this.page(new Query<BrandEntity>().getPage(params), wrapper); return new PageUtils(page); }
3、上传一些有用数据待用;
同时,在前端加上“关联分类”的按钮功能;
二、完成关联分类功能
在电商系统中,每一个品牌都应该拥有自己的分类;
同时,一个品牌可能不止会关联一个分类,比如小米:可以关联“手机”分类,同时小米还有电视,所以也可能关联“家用电器”分类;
所以,“品牌”和“分类”之间必定是N:N的关系,需要一张中间表;
品牌-分类 关联的模块为:product/categorybrandrelation
1、查询关联列表:
@GetMapping("/catelog/list") //@RequiresPermissions("product:categorybrandrelation:list") public R catelogList(@RequestParam("brandId") Long brandId){ List<CategoryBrandRelationEntity> data = categoryBrandRelationService.list(new QueryWrapper<CategoryBrandRelationEntity>().eq("brand_id", brandId)); return R.ok().put("data", data); }
2、新增:略
3、在修改brand和category的时候,需要更新categorybrandrelation表中的名称:
BrandServiceImpl.java:
@Transactional @Override public void updateDetail(BrandEntity brand) { this.updateById(brand); //更新其他表中的字段 categoryBrandRelationService.updateBrandName(brand.getBrandId(), brand.getName()); }
CategoryBrandRelationServiceImpl.java:
@Override public void updateBrandName(Long brandId, String name) { CategoryBrandRelationEntity relationEntity = new CategoryBrandRelationEntity(); relationEntity.setBrandId(brandId); relationEntity.setBrandName(name); this.update(relationEntity, new UpdateWrapper<CategoryBrandRelationEntity>().eq("brand_id", brandId)); }
关联分类功能就全部完成了;
三、平台属性——规格参数
1、完成新增“规格参数”功能:
Service层核心代码:
@Transactional @Override public void saveAttr(AttrVo attrVo) { AttrEntity attrEntity = new AttrEntity(); BeanUtils.copyProperties(attrVo, attrEntity); this.save(attrEntity); //保存属性与属性分组关联关系 AttrAttrgroupRelationEntity relation = new AttrAttrgroupRelationEntity(); relation.setAttrGroupId(attrVo.getAttrGroupId()); relation.setAttrId(attrEntity.getAttrId()); attrAttrgroupRelationService.save(relation); }
其中AttrVo是在AttrEntity上增加传输值attrGroupId,用来完成attr和attrGroup的关系绑定;
新增成功!
2、获取指定分类的规格参数分页列表
GET /product/attr/base/list/{catelogId}
Service层核心代码:
@Override public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId) { QueryWrapper<AttrEntity> wrapper = new QueryWrapper<>(); String key = (String) params.get("key"); if (catelogId != 0){ wrapper.eq("catelog_id", catelogId); } if (StringUtils.isNoneBlank(key)){ wrapper.and(obj -> obj.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<AttrRespVo> respVos = page.getRecords().stream().map(a -> { AttrRespVo attrRespVo = new AttrRespVo(); BeanUtils.copyProperties(a, attrRespVo); AttrAttrgroupRelationEntity relationEntity = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", a.getAttrId())); if (relationEntity != null) { AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(relationEntity.getAttrGroupId()); attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName()); } CategoryEntity categoryEntity = categoryDao.selectById(a.getCatelogId()); if (categoryEntity != null) { attrRespVo.setCatelogName(categoryEntity.getName()); } return attrRespVo; }).collect(Collectors.toList()); pageUtils.setList(respVos); return pageUtils; }
效果如下:
3、“规格参数”的修改功能,能够回显所属分类的“级联菜单”;
GET /product/attr/info/{attrId}
Service层核心代码:
@Override public AttrRespVo getAttrInfo(Long attrId) { AttrRespVo attrRespVo = new AttrRespVo(); AttrEntity attrEntity = this.getById(attrId); BeanUtils.copyProperties(attrEntity, attrRespVo); //查询分组名称 AttrAttrgroupRelationEntity relationEntity = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getAttrId())); if (relationEntity != null) { attrRespVo.setAttrGroupId(relationEntity.getAttrGroupId()); AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(relationEntity.getAttrGroupId()); if (attrGroupEntity != null){ attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName()); } } //查询分类的详细路径catelogPath if (attrEntity.getCatelogId() != 0){ Long[] catelogPath = categoryService.findCatelogPath(attrEntity.getCatelogId()); attrRespVo.setCatelogPath(catelogPath); } return attrRespVo; }
4、“规格参数”修改接口:
Service层核心代码:
@Override public void updateAttr(AttrVo attrVo) { AttrEntity attrEntity = new AttrEntity(); BeanUtils.copyProperties(attrVo, attrEntity); this.updateById(attrEntity); //修改分组关联 AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity(); relationEntity.setAttrId(attrVo.getAttrId()); relationEntity.setAttrGroupId(attrVo.getAttrGroupId()); Integer count = attrAttrgroupRelationDao.selectCount(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrVo.getAttrId())); if (count > 0){ attrAttrgroupRelationDao.update(relationEntity, new UpdateWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrVo.getAttrId())); }else { attrAttrgroupRelationDao.insert(relationEntity); } }
四、平台属性——销售属性
销售属性和基本属性一样,使用的是attr表,唯一不一样的地方是:
attr_type:1基本属性;0销售属性;
还有当为销售属性的时候是没有属性分组的概念的,所以在Service的代码中多次要进行判断:
@Override public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId, String type) { QueryWrapper<AttrEntity> wrapper = new QueryWrapper<>(); String key = (String) params.get("key"); wrapper.eq("attr_type", "base".equalsIgnoreCase(type)? 1 : 0); if (catelogId != 0){ wrapper.eq("catelog_id", catelogId); } if (StringUtils.isNoneBlank(key)){ wrapper.and(obj -> obj.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<AttrRespVo> respVos = page.getRecords().stream().map(a -> { AttrRespVo attrRespVo = new AttrRespVo(); BeanUtils.copyProperties(a, attrRespVo); //设置分组信息,只有基本属性才有分组 if ("base".equalsIgnoreCase(type)){ AttrAttrgroupRelationEntity relationEntity = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", a.getAttrId())); if (relationEntity != null) { AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(relationEntity.getAttrGroupId()); attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName()); } } //设置分类信息 CategoryEntity categoryEntity = categoryDao.selectById(a.getCatelogId()); if (categoryEntity != null) { attrRespVo.setCatelogName(categoryEntity.getName()); } return attrRespVo; }).collect(Collectors.toList()); pageUtils.setList(respVos); return pageUtils; } @Override public AttrRespVo getAttrInfo(Long attrId) { AttrRespVo attrRespVo = new AttrRespVo(); AttrEntity attrEntity = this.getById(attrId); BeanUtils.copyProperties(attrEntity, attrRespVo); //查询分组名称 if (attrEntity.getAttrType() == 1){ AttrAttrgroupRelationEntity relationEntity = attrAttrgroupRelationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getAttrId())); if (relationEntity != null) { attrRespVo.setAttrGroupId(relationEntity.getAttrGroupId()); AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(relationEntity.getAttrGroupId()); if (attrGroupEntity != null){ attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName()); } } } //查询分类的详细路径catelogPath if (attrEntity.getCatelogId() != 0){ Long[] catelogPath = categoryService.findCatelogPath(attrEntity.getCatelogId()); attrRespVo.setCatelogPath(catelogPath); } return attrRespVo; } @Override public void updateAttr(AttrVo attrVo) { AttrEntity attrEntity = new AttrEntity(); BeanUtils.copyProperties(attrVo, attrEntity); this.updateById(attrEntity); //修改分组关联 if (attrVo.getAttrType() == 1){ AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity(); relationEntity.setAttrId(attrVo.getAttrId()); relationEntity.setAttrGroupId(attrVo.getAttrGroupId()); Integer count = attrAttrgroupRelationDao.selectCount(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrVo.getAttrId())); if (count > 0){ attrAttrgroupRelationDao.update(relationEntity, new UpdateWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrVo.getAttrId())); }else { attrAttrgroupRelationDao.insert(relationEntity); } } }
五、分组关联基本属性
再来回顾一下这张图:我们需要将“属性分组”与“属性”建立关系:
1、获取属性分组关联的所有基本属性:——销售属性没有分组信息
GET /product/attrgroup/{attrgroupId}/attr/relation
Service层核心代码:
//根据分组Id查找所有关联的基本属性————销售属性没有分组信息 @Override public List<AttrEntity> getRelationAttr(Long attrgroupId) { List<AttrAttrgroupRelationEntity> relations = attrAttrgroupRelationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id", attrgroupId)); List<Long> ids = relations.stream().map(AttrAttrgroupRelationEntity::getAttrId).collect(Collectors.toList()); return (List<AttrEntity>) this.listByIds(ids); }
2、删除属性与分组的关联关系:
POST /product/attrgroup/attr/relation/delete
AttrGroupController.java:
@PostMapping("/attr/relation/delete") public R deleteRelation(@RequestBody AttrGroupRelationVo[] vos){ attrService.deleteRelation(vos); return R.ok(); }
AttrServiceImpl.java:
@Override public void deleteRelation(AttrGroupRelationVo[] vos) { List<AttrAttrgroupRelationEntity> collect = Arrays.asList(vos).stream().map(r -> { AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity(); BeanUtils.copyProperties(r, relationEntity); return relationEntity; }).collect(Collectors.toList()); attrAttrgroupRelationDao.deleteBatchRelation(collect); }
Dao层Mapper中遍历:可直接批量删除记录:
<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>
3、新增关联时,先查询出当前未跟自己关联的属性列表:
且所关联的属性所属分类 必须 与属性分组所属分类 一样;即catelogId一样;
GET /product/attrgroup/{attrgroupId}/noattr/relation
Service层核心代码:
/** * 获取当前分组可以关联的基本属性列表: * 1、属性必须与本分组属于同一个分类; * 2、这个属性,必须没有被“本分类”下的“其他分组”关联过 * @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> groups = attrGroupDao.selectList(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId)); //2、查找到这些分组关联的所有属性 List<Long> groupIds = groups.stream().map(AttrGroupEntity::getAttrGroupId).collect(Collectors.toList()); List<AttrAttrgroupRelationEntity> binds = attrAttrgroupRelationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().in("attr_group_id", groupIds)); //3、分页查询出那些“本分类下”,且不再binds中的基本属性列表 List<Long> collect = binds.stream().map(AttrAttrgroupRelationEntity::getAttrId).collect(Collectors.toList()); QueryWrapper<AttrEntity> wrapper = new QueryWrapper<AttrEntity>().eq("catelog_id", catelogId).eq("attr_type", 1); if (!CollectionUtils.isEmpty(collect)){ wrapper.notIn("attr_id", collect); } String key = params.get("key").toString(); if (StringUtils.isNoneBlank(key)){ wrapper.and(obj -> obj.eq("attr_id", key).or().like("attr_name", key)); } IPage<AttrEntity> page = this.page(new Query<AttrEntity>().getPage(params), wrapper); return new PageUtils(page); }
4、新增“属性分组”与“属性”的关联:
POST /product/attrgroup/attr/relation
Service层核心代码如下:
@Override public void addRelations(AttrGroupRelationVo[] vos) { List<AttrAttrgroupRelationEntity> collect = Arrays.asList(vos).stream().map(v -> { AttrAttrgroupRelationEntity entity = new AttrAttrgroupRelationEntity(); entity.setAttrId(v.getAttrId()); entity.setAttrGroupId(v.getAttrGroupId()); return entity; }).collect(Collectors.toList()); this.saveBatch(collect); }
最终效果:
至此,平台属性(规格属性、销售属性)部分的代码就全部实现了: