1.属性分组
三级分类中有产品,产品可对应多个属性分组(例如手机有主体和屏幕两个属性分组),每个属性分组又可对应多个属性(例如主体可以包括上市年份,入网时间等)。
前端:attrgroup.vue
后端:AttrGroupController AttrGroupServive AttrGroupEntity
数据库表明:pms_attr_group
(1)查询属性分组列表
前端请求
getDataList() {
this.dataListLoading = true;
this.$http({
url: this.$http.adornUrl(
`/gulimallproduct/attrgroup/list/${this.catId}`
),
method: "get",
params: this.$http.adornParams({
page: this.pageIndex,
limit: this.pageSize,
key: this.dataForm.key,
}),
后端接收
@RequestMapping("/list/{catelogId}")
public R list(@RequestParam Map<String, Object> params,
@PathVariable("catelogId") Long catelogId){
// PageUtils page = attrGroupService.queryPage(params);
PageUtils page = attrGroupService.queryPage(params,catelogId);
return R.ok().put("page", page);
}
请求中会带一个三级分类id,因为可能会通过三级分类列表来获取属性分组
queryPage方法:
@Override
public PageUtils queryPage(Map<String, Object> params, Long catelogId) {
//可能通过搜索查找属性分组,所以先检查key,用户如果输入id就精确查找,如果输入名字就模糊查找
String key = (String) params.get("key");
//select * from pms_attr_group where catelog_id=? and (attr_group_id=key or attr_group_name like %key%)
QueryWrapper<AttrGroupEntity> wrapper = new QueryWrapper<AttrGroupEntity>();
if(!StringUtils.isEmpty(key)){
// wrapper.and((obj)->{
wrapper.eq("attr_group_id",key).or().like("attr_group_name",key);
//});
}
//如果三级分类id为0,就查询所有,否则根据三级分类id查询
if( catelogId == 0){
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);
}
}
(2)修改属性分组
修改时需要根据属性分组id回显数据,然后修改完保存数据
前端请求
`/gulimallproduct/attrgroup/info/${this.dataForm.attrGroupId}`
后端接收请求
@RequestMapping("/info/{attrGroupId}")
public R info(@PathVariable("attrGroupId") Long attrGroupId){
AttrGroupEntity attrGroup = attrGroupService.getById(attrGroupId);
Long catelogId = attrGroup.getCatelogId();
Long[] path = categoryService.findCatelogPath(catelogId);
attrGroup.setCatelogPath(path);
return R.ok().put("attrGroup", attrGroup);
}
先根据属性分组id获取到属性分组的各个属性,然后获取到三级分类id,根据三级分类id获取到所属分类进行回显
findCatelogPath方法:
@Override
public Long[] findCatelogPath(Long catelogId) {
List<Long> paths = new ArrayList<>();
List<Long> parentPath = findParentPath(catelogId, paths);
Collections.reverse(parentPath);
return parentPath.toArray(new Long[parentPath.size()]);
}
//225,25,2
private List<Long> findParentPath(Long catelogId,List<Long> paths){
//1、收集当前节点id
paths.add(catelogId);
CategoryEntity byId = this.getById(catelogId);
if(byId.getParentCid()!=0){
findParentPath(byId.getParentCid(),paths);
}
return paths;
}
根据当前节点id递归查找父节点id,知道父节点id为0。然后将节点id集合反转返回
2.规格参数
操作的数据库:pms_attr
(1)规格参数新增
后端接收:
/**
* 保存 //这里传入attrvo属性,这是自定义的一个属性,为了多传一些实体类没有的属性。
*/
@RequestMapping("/save")
public R save(@RequestBody AttrVo attr){
attrService.saveAttr(attr);
return R.ok();
}
saveAttr方法:
@Override
public void saveAttr(AttrVo attr) {
//先保存实体类所有的数据,也就是属性表中的数据
AttrEntity attrEntity = new AttrEntity();
//spring工具类,拷贝两个类的属性,第一个参数源实体类,第二个参数目标实体类
BeanUtils.copyProperties(attr,attrEntity);
this.save(attrEntity);
//保存关联关系 只有base属性才会有分组 而且传过来的attrvo类中必须有分组id,不然会报空指针异常
if(attr.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode() && attr.getAttrGroupId()!=null) {
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
relationEntity.setAttrGroupId(attr.getAttrGroupId());
relationEntity.setAttrId(attrEntity.getAttrId());
relationDao.insert(relationEntity); //存到属性属性分组数据库表中
}
}
(2)规格参数列表
后端接收:
//传入分页参数和分类id还有一个type 这是判断是查询基础属性还是sale属性的
@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);
}
queryBaseAttrPage方法:
//查询属性列表 传入分页参数 和分类id(因为可能通过分类列表点击查询)
//查询规格参数和销售属性就是通过attr_type这个字段,1就是base属性0就是sale属性
@Override
public PageUtils queryBaseAttrPage(Map<String, Object> params, Long catelogId, String type) {
//先定义条件 判断传过来的attr_type是base就是1否则sale是0 属性数据库表中有这个字段
QueryWrapper<AttrEntity> queryWrapper = new QueryWrapper<AttrEntity>().eq("attr_type",
"base".equalsIgnoreCase(type)?1:0);
//如果是通过分类列表点击 需要先将分类id封装进条件
if(catelogId != 0){
queryWrapper.eq("catelog_id",catelogId);
}
//如果有查询条件 需要将查询条件封装进条件
String key = (String) params.get("key");
if(!StringUtils.isEmpty(key)){
//attr_id attr_name id是精确查找 名字是模糊查找
queryWrapper.and((wrapper)->{
wrapper.eq("attr_id",key).or().like("attr_name",key);
});
}
//创建ipage,传入page和wrapper
IPage<AttrEntity> page = this.page(
//自定义的工具类,获取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();
//先将attr的基本属性拷贝到attrrespvo
BeanUtils.copyProperties(attrEntity, attrRespVo);
//1、设置分类和分组的名字
//relationDao是查询属性和属性分组表,根据属性id查询到一条关联数据,装到AttrAttrgroupRelationEntity
// 这个类中,然后在这个类中查询属性分组id
if("base".equalsIgnoreCase(type)) {//如果传过来的是base才查询分组
AttrAttrgroupRelationEntity attrId = relationDao.selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_id", attrEntity.getAttrId()));
if (attrId != null && attrId.getAttrGroupId() != null) {
//根据上面在中间表中查询出来的属性分组id去属性分组表中查询出属性分组名字
AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrId.getAttrGroupId());
//封装到attrrespvo这个类中准备返回给前端
attrRespVo.setGroupName(attrGroupEntity.getAttrGroupName());
}
}
//根据属性表中的分类id,在分类数据库表中查询出分类对象
CategoryEntity categoryEntity = categoryDao.selectById(attrEntity.getCatelogId());
if (categoryEntity != null) {
//从查出的分类对象获取分类名字,存到attrrespvo中,准备返回给前端
attrRespVo.setCatelogName(categoryEntity.getName());
}
return attrRespVo;
}).collect(Collectors.toList());
pageUtils.setList(respVos);
return pageUtils;
}
(3)规格参数修改
主要是数据回显
后端接收:
@RequestMapping("/info/{attrId}")
public R info(@PathVariable("attrId") Long attrId){
// AttrEntity attr = attrService.getById(attrId);
AttrRespVo attr = attrService.getAttrInfo(attrId);
return R.ok().put("attr", attr);
}
getAttrInfo方法:
@Override
public AttrRespVo getAttrInfo(Long attrId) {
AttrRespVo respVo = new AttrRespVo();
AttrEntity attrEntity = this.getById(attrId);
BeanUtils.copyProperties(attrEntity,respVo);
if(attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()){
//1、设置分组信息
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(attrGroupEntity!=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;
}
点击确定修改 后端接收
/**
* 修改
*/
@RequestMapping("/update")
public R update(@RequestBody AttrVo attr){
attrService.updateAttr(attr);
return R.ok();
}
updateAttr方法:
@Override
public void updateAttr(AttrVo attr) {
//修改属性之后更新数据库 先更新属性
AttrEntity attrEntity = new AttrEntity();
BeanUtils.copyProperties(attr,attrEntity);
this.updateById(attrEntity);
//1、修改分组关联
//然后修改属性属性分组关联表
if (attrEntity.getAttrType() == ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode()) {
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);
}
}
}
销售属性和规格参数一样,就是attr_type为0。
(4)查询分组关联
后端接收:
//查询分组的关联属性
@GetMapping("/{attrgroupId}/attr/relation")
public R attrRelation(@PathVariable("attrgroupId") Long attrgroupId){
//调用属性service查询关联属性
List<AttrEntity> entities = attrService.getRelationAttr(attrgroupId);
return R.ok().put("data",entities);
}
getRelationAttr方法:
@Override
public List<AttrEntity> getRelationAttr(Long attrgroupId) {
//先在中间表中根据属性分组id查询出所有的属性条目,
List<AttrAttrgroupRelationEntity> entities = relationDao.selectList(new QueryWrapper<AttrAttrgroupRelationEntity>().eq("attr_group_id", attrgroupId));
//遍历这些条目 获取到其中的属性id
List<Long> attrIds = entities.stream().map((attr) -> {
return attr.getAttrId();
}).collect(Collectors.toList());
if(attrIds == null || attrIds.size() == 0){
return null;
}
//如果属性id不为空,就在属性表中查询属性进行返回
Collection<AttrEntity> attrEntities = this.listByIds(attrIds);
return (List<AttrEntity>) attrEntities;
}
(5)删除分组关联
后端接收
//删除分组的关联属性
@PostMapping("/attr/relation/delete")
public R deleteRelation(@RequestBody AttrGroupRelationVo[] vos){
//调用属性service的方法,传入AttrGroupRelationVo数组
attrService.deleteRelation(vos);
return R.ok();
}
deleteRelation方法:
@Override
public void deleteRelation(AttrGroupRelationVo[] vos) {
//relationDao.delete(new QueryWrapper<>().eq("attr_id",1L).eq("attr_group_id",1L));
//这种删除方式为写sql语句的方式,定义方法,在dao中声明,在xml中写sql语句
//将传过来的数组转化为list集合进行遍历,
// List<AttrAttrgroupRelationEntity> entities = Arrays.asList(vos).stream().map((item) -> {
// //将传过来的AttrGroupRelationVo类转化为AttrAttrgroupRelationEntity类
// AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
// BeanUtils.copyProperties(item, relationEntity);
// return relationEntity;
// }).collect(Collectors.toList());
//批量删除
//relationDao.deleteBatchRelation(entities);
//这种方法是调用mybatisplus的批量删除方法,不需要写sql语句
List<Long> ids = Arrays.asList(vos).stream().map((item) -> {
//将传过来的AttrGroupRelationVo类转化为AttrAttrgroupRelationEntity类
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
BeanUtils.copyProperties(item, relationEntity);
return relationEntity.getAttrId();
}).collect(Collectors.toList());
//调用批量删除方法 这里要调用关联表的方法
attrAttrgroupRelationService.removeByIds(ids);
}
(6)新建关联,要查出所有分组未关联的属性,对,就是这个属性还没有分组,才能被添加进分组
后端接收
//新增关联属性 传入当前属性分组id 和分页参数
///product/attrgroup/{attrgroupId}/noattr/relation
@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);
}
getNoRelationAttr方法:
@Override
public PageUtils getNoRelationAttr(Map<String, Object> params, Long attrgroupId) {
//1、当前分组只能关联自己所属的分类里面的所有属性
AttrGroupEntity attrGroupEntity = attrGroupDao.selectById(attrgroupId);
//查出分类id
Long catelogId = attrGroupEntity.getCatelogId();
//2、当前分组只能关联别的分组没有引用的属性
//2.1)、当前分类下的所有分组(也包括自己的这个分组,因为自己这组关联的也不能再关联了),传入当前的分类id,查出所有分组
List<AttrGroupEntity> group = attrGroupDao.selectList(new QueryWrapper<AttrGroupEntity>().eq("catelog_id", catelogId));
List<Long> collect = group.stream().map(item -> {
//获取到这些属性分组id
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 -> {
//获取到所有属性id
return item.getAttrId();
}).collect(Collectors.toList());
//2.3)、从当前分类的所有属性中移除这些属性;根据属性id
//首先要满足自己所属的分类,然后要是base属性,
QueryWrapper<AttrEntity> wrapper = new QueryWrapper<AttrEntity>().eq("catelog_id", catelogId).eq("attr_type",ProductConstant.AttrEnum.ATTR_TYPE_BASE.getCode());
//然后排除其他属性,如果其他属性不为空的话,从最开始查出的所有属性id集合中排除其他的属性id
if(attrIds!=null && attrIds.size()>0){
wrapper.notIn("attr_id", attrIds);
}
//模糊查询
String key = (String) params.get("key");
if(!StringUtils.isEmpty(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;
}
保存关联:
后端接收:
///product/attrgroup/attr/relation
@PostMapping("/attr/relation")
public R addRelation(@RequestBody List<AttrGroupRelationVo> vos){
relationService.saveBatch(vos);
return R.ok();
}
saveBatch方法:
@Override
public void saveBatch(List<AttrGroupRelationVo> vos) {
//传过来的是个vo,要转化成真正的实体类,调用方法进行保存
List<AttrAttrgroupRelationEntity> collect = vos.stream().map(item -> {
AttrAttrgroupRelationEntity relationEntity = new AttrAttrgroupRelationEntity();
BeanUtils.copyProperties(item, relationEntity);
return relationEntity;
}).collect(Collectors.toList());
this.saveBatch(collect);
}