一、完善品牌管理功能
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);
}
最终效果:

至此,平台属性(规格属性、销售属性)部分的代码就全部实现了:




