引入分页插件
目前无分页数据
引入分页插件
package com.zhouzhou.gulimall.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.zhouzhou.gulimall.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;
}
}
品牌管理
品牌的模糊查询接口
@Override
public PageUtils queryPage(Map<String, Object> params) {
//1. 获取 key
String key = (String) params.get("key");
QueryWrapper<BrandEntity> queryWrapper = new QueryWrapper<>();
if (!StringUtils.isEmpty(key)){
queryWrapper.eq("brand_id", key).or().like("name", key);
}
IPage<BrandEntity> page = this.page(
new Query<BrandEntity>().getPage(params),
queryWrapper
);
return new PageUtils(page);
}
测试
添加有用的数据
common 中导入 brand-select 和 category-cascade 两个组件
覆盖 brand 的两个vue 文件,下一小节实现关联分类的功能
关联分类实现
品牌和分类是多对多的关系
获得与品牌关联的分类
/**
* 获取当前品牌关联的所有分类列表
*/
@GetMapping("/catelog/list")
public R list(@RequestParam("brandId") Long brandId){
List<CategoryBrandRelationEntity> data = categoryBrandRelationService.list(
new QueryWrapper<CategoryBrandRelationEntity>().eq("brand_id", brandId));
return R.ok().put("data", data);
}
![image-20210225150950036](https://i-blog.csdnimg.cn/blog_migrate/7dcbfe2a4172ddbe0449e550eb2a48df.png)
新增品牌与分类关联关系
考虑到电商系统,没有设计外键,这里在存放id的时候也存放了名字,生成的代码中没有名字,需要重写
// CategoryBrandRelationController
/**
* 保存
*/
@RequestMapping("/save")
public R save(@RequestBody CategoryBrandRelationEntity categoryBrandRelation){
categoryBrandRelationService.saveDetail(categoryBrandRelation);
return R.ok();
}
// CategoryBrandRelationServiceImpl
@Override
public void saveDetail(CategoryBrandRelationEntity categoryBrandRelation) {
Long brandId = categoryBrandRelation.getBrandId();
Long catelogId = categoryBrandRelation.getCatelogId();
// 1.查询详细名字
BrandEntity brandEntity = brandDao.selectById(brandId);
CategoryEntity categoryEntity = categoryDao.selectById(catelogId);
categoryBrandRelation.setBrandName(brandEntity.getName());
categoryBrandRelation.setCatelogName(categoryEntity.getName());
this.save(categoryBrandRelation);
}
![image-20210225151741391](https://i-blog.csdnimg.cn/blog_migrate/87f1228c6cca96e32f00ebf35b6b3195.png)
![image-20210225151757865](https://i-blog.csdnimg.cn/blog_migrate/f01037a7aef71fdddcb641205a7d328b.png)
冗余数据的级联更新
冗余设计需要实时更新
![image-20210225154212945](https://i-blog.csdnimg.cn/blog_migrate/ec545cb4fed6b5e4701f81607bd8b3ab.png)
![image-20210225154153849](https://i-blog.csdnimg.cn/blog_migrate/1a5356ba5910f420da82d273592f8dec.png)
前端这里需要添加一个依赖
npm install pubsub-js@1.8.0 --save
并且在 main 函数挂载
import PubSub from "pubsub-js"
Vue.prototype.PubSub = PubSub;
brand 冗余 保证一直
// file: BrandController
/**
* 修改
*/
@RequestMapping("/update")
// @RequiresPermissions("product:brand:update")
public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand) {
brandService.updateDeatil(brand);
return R.ok();
}
// file: BrandServiceImpl
@Override
public void updateDeatil(BrandEntity brand) {
// 保证冗余字段的数据一致
this.updateById(brand);
if (!StringUtils.isEmpty(brand.getName())) {
// 同步更新其他关联表中的数据
categoryBrandRelationService.updateBrand(brand.getBrandId(), brand.getName());
//TODO 更新其他关联
}
}
// file: CategoryBrandRelationServiceImpl
@Override
public void updateBrand(Long brandId, String name) {
CategoryBrandRelationEntity relationEntity = new CategoryBrandRelationEntity();
relationEntity.setBrandId(brandId);
relationEntity.setBrandName(name);
this.update(relationEntity, new QueryWrapper<CategoryBrandRelationEntity>().eq("brand_id", brandId));
}
这里测试修改品牌名,关联分类中显示的品牌名也会改变
![image-20220523135201572](https://i-blog.csdnimg.cn/blog_migrate/16cca740aeeae4fd7b1f2cae6081e624.png)
![image-20220523135144223](https://i-blog.csdnimg.cn/blog_migrate/e8961a92ebbff3767c05f62416324355.png)
同理,分类修改时也需要同步修改所有引用的中间表
这里改成在dao层实现
// file: CategoryController
/**
* 修改
*/
@RequestMapping("/update")
public R update(@RequestBody CategoryEntity category) {
categoryService.updateCascade(category);
return R.ok();
}
/**
* 级联更新所有关联数据
*
* @param category
*/
@Override
public void updateCascade(CategoryEntity category) {
this.updateById(category);
this.baseMapper.updateCategory(category.getCatId(), category.getName());
}
// 这里前面都一样,但是到了CategoryBrandRelationServiceImpl 的时候,在mapper层进行重写
@Override
public void updateCategory(Long catId, String name) {
this.baseMapper.updateCategory(catId, name);
}
@Mapper
public interface CategoryBrandRelationDao extends BaseMapper<CategoryBrandRelationEntity> {
void updateCategory(@Param("catId") Long catId, @Param("name") String name);
}
<update id="updateCategory">
UPDATE `pms_category_brand_relation` SET catelog_name=#{name} where catelog_id=#{catId}
</update>
一个用的 QueryWrapper
一个用的 mapper
这里测试修改分类名称
![image-20210225164641276](https://i-blog.csdnimg.cn/blog_migrate/36d3cb2fc8d4813c01645dfbddeafa1b.png)
![image-20210225164649288](https://i-blog.csdnimg.cn/blog_migrate/bc5fbba17354a1c85c63575ec7193c33.png)
最后 加上事务控制
@Override
@Transactional
public void updateDeatil(BrandEntity brand) {
// 保证冗余字段的数据一致
this.updateById(brand);
if (!StringUtils.isEmpty(brand.getName())) {
// 同步更新其他关联表中的数据
categoryBrandRelationService.updateBrand(brand.getBrandId(), brand.getName());
//TODO 更新其他关联
}
}
@Transactional
@Override
public void updateCascade(CategoryEntity category) {
this.updateById(category);
categoryBrandRelationService.updateCategory(category.getCatId(), category.getName());
}
也是由于 MyabtisConfig
里面添加了事务相关的配置
总结
品牌管理这里重点在于冗余数据一致性,总结起来实现总共有两个点:
- 中间表带上两张表详细字段
![image-20220527144542503](https://i-blog.csdnimg.cn/blog_migrate/34b74112464db0afd0d5af283a31164e.png)
- 两张关联的表在修改和新增的时候都需要写冗余的中间表
这里如果不设计冗余表,每次查询关联数据的时候都需要使用 join 查询