8.商品服务-属性分组+品牌管理
1.SPU和SKU
SPU:是商品信息聚合的最小单位,是一组可复用,易检索的标准化信息集合,该集合描述了一个产品的特性--相对于sku是类的概念--基本属性
SKU:顾客真正买的spu,比如华为的mate40蓝色 256G内存的手机--相对于spu是对象的概念---销售属性
执行admin.sql的sys_menu表获取到菜单信息
2.从这里开始前端的代码就不讲了--以后都是对照接口做后端业务
来编写获取分类属性分组的功能
3.获取分类属性分组
具体类方法实现
//分页查询,需要匹配key的模糊查询 @Override public PageUtils queryPage(Map<String, Object> params, Long catlogId) { //如果没有三级分类的id传过来,那么catlogId等于0,那就传所有的(前端规定) if(catlogId==0){ IPage<AttrGroupEntity> page = this.page(new Query<AttrGroupEntity>().getPage(params), new QueryWrapper<AttrGroupEntity>());//没有任何条件的情况下就是查所有 return new PageUtils(page);//利用封装好的工具类进行解析 }else{ //需要的sql语句 //select * from pms_attr_group where catelog_id=? and (attr_group_name=key or attr_group_id like %key%) //key就是检索框输入的东西 String key= (String) params.get("key"); QueryWrapper<AttrGroupEntity> wrapper = new QueryWrapper<AttrGroupEntity>().eq("catelog_id",catlogId);//三级分类id相等 if(!StringUtils.isEmpty(key)){ wrapper.and((obj)->{ obj.eq("attr_group_id",key).or().like("attr_group_name",key); }); } IPage<AttrGroupEntity> page = this.page(new Query<AttrGroupEntity>().getPage(params), wrapper); return new PageUtils(page); } }
Controller调用:
/** * 列表,关键字索引,分类查询 */ @RequestMapping("/list/{catelogId}") public R list(@RequestParam Map<String, Object> params,@PathVariable("catelogId") Long catlogId){ PageUtils page = attrGroupService.queryPage(params,catlogId);//拿到提交过来的参数和三级分类的id return R.ok().put("page", page); }
postman测试
sql语句打印
Preparing: SELECT attr_group_id,attr_group_name,sort,descript,icon,catelog_id FROM pms_attr_group WHERE (catelog_id = ? AND (attr_group_id = ? OR attr_group_name LIKE ?))
前端联调测试
点击手机,根据手机的key和三级分类发出请求
查询芯片的芯关键字
4.对之前的分类维护做一个处理
当前端在新增的时候,点到最后一层子目录还会显示子目录,这样就没有办法输入了
这是因为最后一个子目录虽然没有children字段,但是还是带上了
使用一个注解可以解决
再次请求发现已经不再带有children字段了,前端联调成功
5.完善属性分组
在我们点击修改的时候,属性分类不能回显,后台需要给前台传递一个完整的cid路径
比如手机【2,25,225】
Controller
/** * 信息 */ @RequestMapping("/info/{attrGroupId}") //@RequiresPermissions("product:attrgroup:info") public R info(@PathVariable("attrGroupId") Long attrGroupId){ AttrGroupEntity attrGroup = attrGroupService.getById(attrGroupId); Long catlogId=attrGroup.getCatelogId(); Long[] path=categoryService.findCatelogPath(catlogId); attrGroup.setCatelogPath(path); return R.ok().put("attrGroup", attrGroup); }
实现类
@Override public Long[] findCatelogPath(Long catlogId) { List<Long> path=new ArrayList<>(); findParentPath(catlogId,path); //集合逆序,添加的时候是反着添加的 Collections.reverse(path); return path.toArray(new Long[path.size()]);//转化成数组的时候要指定数组 } //找到父亲id的方法 private List<Long> findParentPath(Long catlogId,List<Long> path){ //收集当前id path.add(catlogId); CategoryEntity entity = this.getById(catlogId); //获得父节点id--递归 Long parentCid = entity.getParentCid(); if(parentCid!=0){ //如果父节点id不为0就一直找 findParentPath(parentCid,path); } return path; }
点击修改已经成功回显了
6.品牌分类关联和级联更新
1.引入分页插件
@Configuration @EnableTransactionManagement//开启事务功能 @MapperScan("com.wuyimin.gulimall.product.dao") public class MybatisConfig { //引入分页插件 @Bean public PaginationInterceptor paginationInterceptor(){ PaginationInterceptor paginationInterceptor=new PaginationInterceptor(); paginationInterceptor.setOverflow(true);//请求页面大于最后页面 false为默认-请求到空数据 true--跳到第一页 paginationInterceptor.setLimit(1000);//每页最大受限1000条 -1不受限制 return paginationInterceptor; } }
可以看到分页已经正常了
2.修改品牌的模糊查询功能--之前实现过这里不赘述了
@Service("brandService") public class BrandServiceImpl extends ServiceImpl<BrandDao, BrandEntity> implements BrandService { @Override public PageUtils queryPage(Map<String, Object> params) { String key= (String) params.get("key"); QueryWrapper<BrandEntity> entityQueryWrapper=new QueryWrapper<>(); if(!StringUtils.isEmpty(key)){ entityQueryWrapper.eq("brand_id",key).or().like("name",key); } IPage<BrandEntity> page = this.page( new Query<BrandEntity>().getPage(params), entityQueryWrapper ); return new PageUtils(page); }
7.关联分类
传入的brand_Id与category_brand_relation表的相关id相同就表示关联
/** * 列表 */ @GetMapping("/catelog/list") public R catelogList(@RequestParam Map<String, Object> params){ String brandId= (String) params.get("brandId"); List<CategoryBrandRelationEntity> data = categoryBrandRelationService. list(new QueryWrapper<CategoryBrandRelationEntity>().eq("brand_id", brandId)); return R.ok().put("data", data); }
原生态的save方法,由于前端并没有传名字的信息,这里会显示为空,在大规模的电商系统来说,关联很耗内存,如果我们能增加两个冗余字段就能避免这种联表查询
后端代码:
/** * 保存 */ @RequestMapping("/save") //@RequiresPermissions("product:categorybrandrelation:save") public R save(@RequestBody CategoryBrandRelationEntity categoryBrandRelation){ categoryBrandRelationService.saveDetail(categoryBrandRelation); return R.ok(); }
@Service("categoryBrandRelationService") public class CategoryBrandRelationServiceImpl extends ServiceImpl<CategoryBrandRelationDao, CategoryBrandRelationEntity> implements CategoryBrandRelationService { @Autowired BrandDao brandDao; @Autowired CategoryDao categoryDao; @Override public PageUtils queryPage(Map<String, Object> params) { IPage<CategoryBrandRelationEntity> page = this.page( new Query<CategoryBrandRelationEntity>().getPage(params), new QueryWrapper<CategoryBrandRelationEntity>() ); return new PageUtils(page); } @Override public void saveDetail(CategoryBrandRelationEntity categoryBrandRelation) { Long brandId = categoryBrandRelation.getBrandId(); Long catelogId = categoryBrandRelation.getCatelogId(); //分别查询品牌名和分类名 BrandEntity brandEntity = brandDao.selectById(brandId); String brandEntityName = brandEntity.getName(); String cateEntityName=categoryDao.selectById(catelogId).getName(); categoryBrandRelation.setBrandName(brandEntityName); categoryBrandRelation.setCatelogName(cateEntityName);//保存 this.save(categoryBrandRelation);//调用自己的save方法保存数据 } }
保证冗余字段的一致性,在你改了其他表的时候,冗余字段也要跟着修改
当我修改了品牌名华为2的时候其关联分类名也应该跟着修改
具体实现:
@RequestMapping("/update") //@RequiresPermissions("product:brand:update") public R update(@RequestBody BrandEntity brand){ brandService.updateDetail(brand); return R.ok(); }
@Autowired private CategoryBrandRelationService categoryBrandRelationService; @Override public void updateDetail(BrandEntity brand) { //保证冗余字段的数据一致 this.updateById(brand); if(!StringUtils.isEmpty(brand.getName())){ //同步更新其他关联表的冗余字段 categoryBrandRelationService.updateBrand(brand.getBrandId(),brand.getName()); //TODO 更新其他的关联信息 } }
@Override public void updateBrand(Long brandId, String name) { CategoryBrandRelationEntity entity = new CategoryBrandRelationEntity(); entity.setBrandId(brandId);//id entity.setBrandName(name);//只有名字是冗余字段,只更新名字就行 this.update(entity,new UpdateWrapper<CategoryBrandRelationEntity>().eq("brand_id",brandId));//updateWrapper }
使用级联更新更新该关联表的另一个属性
/** * 修改 */ @RequestMapping("/update") //@RequiresPermissions("product:category:update") public R update(@RequestBody CategoryEntity category){ categoryService.updateCascade(category); return R.ok(); }
@Override public void updateCascade(CategoryEntity category) { this.updateById(category); categoryBrandRelationService.updateCategory(category.getCatId(),category.getName()); }
@Override public void updateCategory(Long catId, String name) { this.baseMapper.updateCategory(catId,name); }
有两个以上的参数最好用@Param起一个名字
@Mapper public interface CategoryBrandRelationDao extends BaseMapper<CategoryBrandRelationEntity> { void updateCategory(@Param("catId") Long catId,@Param("name") String name); }
装了mybatisX插件之后就可以用这个
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.wuyimin.gulimall.product.dao.CategoryBrandRelationDao"> <!-- 可根据自己的需求,是否要使用 --> <resultMap type="com.wuyimin.gulimall.product.entity.CategoryBrandRelationEntity" id="categoryBrandRelationMap"> <result property="id" column="id"/> <result property="brandId" column="brand_id"/> <result property="catelogId" column="catelog_id"/> <result property="brandName" column="brand_name"/> <result property="catelogName" column="catelog_name"/> </resultMap> <update id="updateCategory"> update `pms_category_brand_relation` set catelog_name=#{name} where catelog_id=#{catId} </update> </mapper>
最后该方法是一个事件,必须具有原子性
同时也要在事务配置文件中添加注解开启事件
这样修改分类名就可以关联到品牌模块了