1.SPU和SKU
SPU:是商品信息聚合的最小单位,是一组可复用,易检索的标准化信息集合,该集合描述了一个产品的特性--相对于sku是类的概念--基本属性
SKU:顾客真正买的spu,比如华为的mate40蓝色 256G内存的手机--相对于spu是对象的概念---销售属性
![](https://i-blog.csdnimg.cn/blog_migrate/c708d0e34043f0fa43ade1bff36adff9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e4891cbdc44924ba49995c5a3adbdd19.png)
![](https://i-blog.csdnimg.cn/blog_migrate/df2dfd6c5b2021e9002a7a4088ca01cc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/eb2381c8404a54d94f153b91ebab5312.png)
执行admin.sql的sys_menu表获取到菜单信息
![](https://i-blog.csdnimg.cn/blog_migrate/3ecf59345ec61dd944821fd74d6c6677.png)
2.从这里开始前端的代码就不讲了--以后都是对照接口做后端业务
来编写获取分类属性分组的功能
![](https://i-blog.csdnimg.cn/blog_migrate/1e6886ac2f88ed963f565ff2482e6c6f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/86320fbbd8e7becb1f7667605b18a296.png)
3.获取分类属性分组
具体类方法实现
![](https://i-blog.csdnimg.cn/blog_migrate/03c7d3b616cd2ca61aa24cd03f10f790.png)
//分页查询,需要匹配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测试
![](https://i-blog.csdnimg.cn/blog_migrate/0c0a69ea705d048e82d4d6e9b5ffa6ac.png)
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和三级分类发出请求
![](https://i-blog.csdnimg.cn/blog_migrate/adb31f2f4022d3e4ffab64e3d00c163f.png)
查询芯片的芯关键字
![](https://i-blog.csdnimg.cn/blog_migrate/250972200b22a8ea7181381962187197.png)
4.对之前的分类维护做一个处理
当前端在新增的时候,点到最后一层子目录还会显示子目录,这样就没有办法输入了
![](https://i-blog.csdnimg.cn/blog_migrate/d7b3b9ebf34353e6e63c2dabb6f3ea85.png)
这是因为最后一个子目录虽然没有children字段,但是还是带上了
![](https://i-blog.csdnimg.cn/blog_migrate/8417aa43dceecc02d02332d3a24d054a.png)
使用一个注解可以解决
![](https://i-blog.csdnimg.cn/blog_migrate/be4583ba84044d20e0bf1fc97ee183f1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/261c2d25c69e30cc56a71213f5d77bc5.png)
再次请求发现已经不再带有children字段了,前端联调成功
![](https://i-blog.csdnimg.cn/blog_migrate/e1d275f19891a81bddc4b190d0646053.png)
5.完善属性分组
在我们点击修改的时候,属性分类不能回显,后台需要给前台传递一个完整的cid路径
![](https://i-blog.csdnimg.cn/blog_migrate/e8380f16c0eb9e4d585509205412d2ed.png)
比如手机【2,25,225】
Controller
![](https://i-blog.csdnimg.cn/blog_migrate/e2726acdc6bccb80cd273e3e7609f9d4.png)
/**
* 信息
*/
@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);
}
实现类
![](https://i-blog.csdnimg.cn/blog_migrate/d02e85caa58d39f35423a9a1a313ebd3.png)
@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;
}
点击修改已经成功回显了
![](https://i-blog.csdnimg.cn/blog_migrate/3de1fdd38159b6712ce6fc5768ed62a1.png)
6.品牌分类关联和级联更新
1.引入分页插件
![](https://i-blog.csdnimg.cn/blog_migrate/9ae7a7bd43746359a2c6cb461fdf7840.png)
@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;
}
}
可以看到分页已经正常了
![](https://i-blog.csdnimg.cn/blog_migrate/1d2ff66af2c521432167fd2e1e1c9a3f.png)
2.修改品牌的模糊查询功能--之前实现过这里不赘述了
![](https://i-blog.csdnimg.cn/blog_migrate/7a8fe988401a083898ffdb860478138e.png)
@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.关联分类
![](https://i-blog.csdnimg.cn/blog_migrate/38b2f7a945cadbb19cfe2d3f91dab5f6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d1fda6e942bee48992ea6b146da61a1d.png)
传入的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);
}
![](https://i-blog.csdnimg.cn/blog_migrate/df7bb26ac32ecb6ca9fb979123da56ab.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c6e3d916b83a513483854702a2ee3e07.png)
原生态的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的时候其关联分类名也应该跟着修改
![](https://i-blog.csdnimg.cn/blog_migrate/08394474bcf8307449d42937afcf16b4.png)
具体实现:
![](https://i-blog.csdnimg.cn/blog_migrate/4b3649056a17a765e62f2fcadb41e41c.png)
@RequestMapping("/update")
//@RequiresPermissions("product:brand:update")
public R update(@RequestBody BrandEntity brand){
brandService.updateDetail(brand);
return R.ok();
}
![](https://i-blog.csdnimg.cn/blog_migrate/929f44b73af7645dca922e82966f60f5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6e6fe43c36774ab7f25eeaed6d2cfa13.png)
@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
}
使用级联更新更新该关联表的另一个属性
![](https://i-blog.csdnimg.cn/blog_migrate/51c8b60eaf9e1767e7753ae5f72c4ae3.png)
/**
* 修改
*/
@RequestMapping("/update")
//@RequiresPermissions("product:category:update")
public R update(@RequestBody CategoryEntity category){
categoryService.updateCascade(category);
return R.ok();
}
![](https://i-blog.csdnimg.cn/blog_migrate/508869ab3dd26512c7103ffd9b328290.png)
@Override
public void updateCascade(CategoryEntity category) {
this.updateById(category);
categoryBrandRelationService.updateCategory(category.getCatId(),category.getName());
}
![](https://i-blog.csdnimg.cn/blog_migrate/0e5f852072ecabaa7bdc988622567a9b.png)
@Override
public void updateCategory(Long catId, String name) {
this.baseMapper.updateCategory(catId,name);
}
![](https://i-blog.csdnimg.cn/blog_migrate/8fe3e351f4ed818580bf9d37cb272094.png)
有两个以上的参数最好用@Param起一个名字
@Mapper
public interface CategoryBrandRelationDao extends BaseMapper<CategoryBrandRelationEntity> {
void updateCategory(@Param("catId") Long catId,@Param("name") String name);
}
装了mybatisX插件之后就可以用这个
![](https://i-blog.csdnimg.cn/blog_migrate/9fd051d34b7b5886f25d2d545e902193.png)
![](https://i-blog.csdnimg.cn/blog_migrate/935859c3f59382b0be3937e552bb4c64.png)
<?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>
最后该方法是一个事件,必须具有原子性
![](https://i-blog.csdnimg.cn/blog_migrate/0c87a14c90e9e093f6f443457b2e09ba.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4675ed5a3160696f7d965c09f3f6f0f0.png)
同时也要在事务配置文件中添加注解开启事件
![](https://i-blog.csdnimg.cn/blog_migrate/1ad40e3d7cfa5a81484fcf49a5770647.png)
这样修改分类名就可以关联到品牌模块了
![](https://i-blog.csdnimg.cn/blog_migrate/92bb7245ec9f74a048538f7bafa99358.png)