七、三级分类--谷粒商城
1.三级分类-查询

1.0后端代码实现-微服务Product
@Service("categoryService") public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService { @Override public PageUtils queryPage(Map<String, Object> params) { IPage<CategoryEntity> page = this.page( new Query<CategoryEntity>().getPage(params), new QueryWrapper<CategoryEntity>() ); return new PageUtils(page); } @Override public List<CategoryEntity> listWithTree() { /*** * 1.查出所有分类 * 2.组装成父子的树形结构 */ //1.查询所有分类 List<CategoryEntity> entities = baseMapper.selectList(null); //2.组装父子结构 List<CategoryEntity> level1Menus = entities.stream().filter(categoryEntity-> categoryEntity.getParentCid() == 0 ).map((menu)->{ menu.setChildren(getChildrens(menu,entities)); return menu; }).sorted((menu1,menu2)->{ return (menu1.getSort()==null?0: menu1.getSort())- (menu2.getSort()==null?0: menu2.getSort()); }).collect(Collectors.toList()); //2.1找到所有的一级分类 根据parentID return level1Menus; } /** * 递归查找所有菜单的子菜单 * @param root 当前菜单 * @param all 所有菜单 * @return */ private List<CategoryEntity>getChildrens(CategoryEntity root,List<CategoryEntity> all){ List<CategoryEntity> children = all.stream().filter(categoryEntity -> { return categoryEntity.getParentCid() == root.getCatId(); }).map(categoryEntity -> { //找到子菜单 categoryEntity.setChildren(getChildrens(categoryEntity,all)); return categoryEntity; }).sorted((menu1,menu2)->{ //菜单排序 return (menu1.getSort()==null?0: menu1.getSort())- (menu2.getSort()==null?0: menu2.getSort()); }).collect(Collectors.toList()); return children; } }
1.1前端代码
<template>
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick"></el-tree>
</template>
<script>
export default {
data() {
return {
data: [],
defaultProps: {
children: 'children',
label: 'label'
}
}
},
components: {},
props:{},
methods: {
handleNodeClick(data) {
console.log(data);
},
getMenus(){
this.$http({
url: this.$http.adornUrl('/gulimallproduct/category/list/tree'),
method: 'get'
}).then(data => {
console.log("成功获取到菜单数据..",data)
})
}
},
//声明周期-创建完成(可以访问this实例)
created(){
this.getMenus();
},
computed: {},
watch: {}
}
</script>
<style>
</style>
1.1.2修改请求根路径到网关

1.2后端代码
在启动项加上@EnableDiscoveryClient注解
后再配置文件application.yml上
cloud: nacos: discovery: server-addr: 127.0.0.1:8848
1.2.4根据请求路径重写路由规则
spring: cloud: gateway: routes: - id : product_route uri: lb://gulimall-product predicates: - Path=/api/gulimallproduct/** filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: admin_route uri: lb://renren-fast predicates: - Path=/api/** filters: - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}
1.2.5配置Nacos-product
bootstrap.properties文件 spring.application.name=gulimall-product spring.cloud.nacos.config.server-addr=127.0.0.1:8848 spring.cloud.nacos.config.namespace=8279a665-8232-45c8-b2f0-4bde76d4775b application.yml文件 spring: datasource: username: root password: root url: jdbc:mysql://192.168.56.10:3306/gulimall_pms?useUnicode=true&characterEncoding=utf8&useSSL=false driver-class-name: com.mysql.cj.jdbc.Driver application: name: gulimall-product cloud: nacos: discovery: server-addr: 127.0.0.1:8848 mybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml global-config: db-config: id-type: auto server: port: 10000
2.解决跨域问题

2.1使用Nginx部署为同一域

2.2配置当次请求允许跨域-自定义filter

package com.atguigu.gulimall.gateway.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.reactive.CorsWebFilter; import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource; @Configuration public class GulimallCorsConfiguration { @Bean public CorsWebFilter corsWebFilter(){ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); //1、配置跨域 corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.addAllowedOrigin("*"); corsConfiguration.setAllowCredentials(true); source.registerCorsConfiguration("/**",corsConfiguration); return new CorsWebFilter(source); } }
3.三级分类-删除菜单


3.1前端代码
3.1.1页面代码
<template> <el-tree :data="menus" :props="defaultProps" :expand-on-click-node="false" show-checkbox node-key="catId" > <span class="custom-tree-node" slot-scope="{ node, data }"> <span>{{ node.label }}</span> <span> <el-button v-if="node.level <= 2" type="text" size="mini" @click="() => append(data)" > Append </el-button> <el-button v-if="node.childNodes.length == 0" type="text" size="mini" @click="() => remove(node, data)" > Delete </el-button> </span> </span> </el-tree> </template> <script> export default { data() { return { menus: [], defaultProps: { children: "children", label: "name", }, }; }, components: {}, props: {}, methods: { getMenus() { this.$http({ url: this.$http.adornUrl("/gulimallproduct/category/list/tree"), method: "get", }).then(({ data }) => { console.log("成功获取到菜单数据..", data.data); this.menus = data.data; }); }, append(data) { console.log("append", data); }, remove(node, data) { console.log("remove", node, data); }, }, //声明周期-创建完成(可以访问this实例) created() { this.getMenus(); }, computed: {}, watch: {}, }; </script> <style> </style>
3.1.2发送POST请求模板
this.$http({ url: this.$http.adornUrl("/gulimallproduct/category/delete"), method: "post", data: this.$http.adornData(ids, false), }).then(({ data }) => { console.log("删除成功") });
3.1.3发送get请求模板
"http-get 请求": { "prefix": "httpget", "body": [ "this.\\$http({", "url: this.\\$http.adornUrl(''),", "method: 'get',", "params: this.\\$http.adornParams({})", "}).then(({data}) => {", "})" ], "description": "httpGET 请求" }
3.1.4删除代码
remove(node, data) { var ids = [data.catId]; //弹框提示 this.$confirm(`是否删除【${data.name}】菜单?`, "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }).then(() => { this.$http({ url: this.$http.adornUrl("/gulimallproduct/category/delete"), method: "post", data: this.$http.adornData(ids, false), }).then(({ data }) => { this.$message({ message: "菜单删除成功", type: "success", }); //更新页面 this.getMenus(); //设置默认需要展开的菜单 this.expandedKey=[node.parent.data.catId] }); }) .catch(() => {}); console.log("remove", node, data); },
3.2后端代码
3.2.1逻辑删除
application.yml mybatis-plus: global-config: db-config: logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2) logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
实体类字段上加上@TableLogic注解
@TableLogic private Integer deleted;
4.三级分类-添加子菜单
4.2前端代码
//添加子菜单 append(data) { console.log("append", data); this.dialogVisible = true; this.category.parentCid = data.catId; this.category.catLevel = data.catLevel * 1 + 1; }, //添加三级分类 addCategory() { this.$http({ url: this.$http.adornUrl("/product/category/save"), method: "post", data: this.$http.adornData(this.category, false), }).then(({ data }) => { this.$message({ message: "菜单保存成功", type: "success", }); //关闭对话框 this.dialogVisible = false; //更新页面 this.getMenus(); //设置默认需要展开的菜单 this.expandedKey = [this.category.parentCid]; }); },
4.3后端代码
@RequestMapping("/save") //@RequiresPermissions("product:category:save") public R save(@RequestBody CategoryEntity category){ categoryService.save(category); return R.ok(); }
5.三级分类-修改
//修改三级分类 edit(data) { console.log("要修改的的数据", data); this.dialogType = "edit"; this.title = "修改分类"; this.dialogVisible = true; //回显,发送请求获取最新数据 this.$http({ url: this.$http.adornUrl(`/product/category/info/${data.catId}`), method: "get", }).then(({ data }) => { //请求成功 console.log("要回显的数据", data); this.category.name = data.data.name; this.category.catId = data.data.catId; this.category.icon = data.data.icon; this.category.productUnit = data.data.productUnit; this.category.parentCid = data.data.parentCid; this.category.catLevel = data.data.catLevel; this.category.sort = data.data.sort; this.category.showStatus = data.data.showStatus; }); }, editCategory() { //发送只需要修改的数据 var { catId, name, icon, productUnit } = this.category; this.$http({ url: this.$http.adornUrl("/product/category/update"), method: "post", data: this.$http.adornData({ catId, name, icon, productUnit }, false), }).then(({ data }) => { this.$message({ message: "菜单修改成功", type: "success", }); //关闭对话框 this.dialogVisible = false; //更新页面 this.getMenus(); //设置默认需要展开的菜单 this.expandedKey = [this.category.parentCid]; }); },
5.2后端代码
@RequestMapping("/update") //@RequiresPermissions("product:category:update") public R update(@RequestBody CategoryEntity category){ categoryService.updateById(category); return R.ok(); }
6.三级分类-拖拽节点修改父子关系
//拖拽修改父子关系 batchSave() { this.$http({ url: this.$http.adornUrl("/product/category/update/sort"), method: "post", data: this.$http.adornData(this.updateNodes, false), }).then(({ data }) => { this.$message({ message: "菜单顺序修改成功", type: "success", }); //更新页面 this.getMenus(); //设置默认需要展开的菜单 this.expandedKey = this.pCid; this.updateNodes = []; this.maxLevel = 0; //this.pCid = 0; }); }, allowDrop(draggingNode, dropNode, type) { //被拖动的当前节点以及所在的父节点的总层数不能大于3 //1.被拖动的当前节点总层数 var level = this.countNodeLevel(draggingNode); //当前正在拖动的节点+父节点所在的深度不大于3即可 let deep = Math.abs(this.maxLevel - draggingNode.level) + 1; if (type == "inner") { return deep + dropNode.level <= 3; } else { return deep + dropNode.parent.level <= 3; } }, countNodeLevel(node) { //找出所有自己点,求出最大深度 if (node.childNodes != null && node.childNodes.length > 0) { for (let i = 0; i < node.childNodes.length; i++) { if (node.childNodes[i].level > this.maxLevel) { this.maxLevel = node.childNodes[i].level; } this.countNodeLevel(node.childNodes[i]); } } }, handleDrop(draggingNode, dropNode, dropType, ev) { console.log("handleDrop: ", dropNode.label, dropType); //当前节点最新的父节点id let pCid = 0; let siblings = null; if (dropType == "before" || dropType == "after") { pCid = dropNode.parent.data.catId == undefined ? 0 : dropNode.parent.data.catId; siblings = dropNode.parent.childNodes; } else { pCid = dropNode.data.catId; siblings = dropNode.childNodes; } this.pCid.push(pCid); //当前拖拽的节点的最新顺序 for (let i = 0; i < siblings.length; i++) { if (siblings[i].data.catId == draggingNode.data.catId) { //如果遍历当前拖拽的节点 let catLevel = draggingNode.level; if (siblings[i].level != draggingNode.level) { //当前节点的层级发生变化 catLevel = siblings[i].level; //修改子节点的层级 this.updateChildNodeLevel(siblings[i]); this.updateNodes.push({ catId: siblings[i].data.catId, sort: i, parentCid: pCid, catLevel: catLevel, }); } this.updateNodes.push({ catId: siblings[i].data.catId, sort: i, parentCid: pCid, }); } else { this.updateNodes.push({ catId: siblings[i].data.catId, sort: i }); } } //当前拖拽节点的最新层级 }, updateChildNodeLevel(node) { if (node.childNodes.length > 0) { for (let i = 0; i < node.childNodes.length; i++) { var cNode = node.childNodes[i].data; this.updateNodes.push({ catId: cNode.catId, catLevel: node.childNodes[i].level, }); this.updateChildNodeLevel(node.childNodes[i]); } } },
6.2后端代码
@RequestMapping("/delete") // @RequiresPermissions("product:category:delete") public R delete(@RequestBody Long[] catIds){ //1.检测当前删除的菜单是否被别的地方引用 //categoryService.removeByIds(Arrays.asList(catIds)); categoryService.removeMenuByIds(Arrays.asList(catIds)); return R.ok(); }
7.整体设计
7.1前端全代码
<template>
<div>
<el-switch v-model="draggable" active-text="开启拖拽" inactive-text="关闭拖拽"></el-switch>
<el-button v-if="draggable" @click="batchSave">批量保存</el-button>
<el-button type="danger" @click="batchDelete">批量删除</el-button>
<el-tree
:data="menus"
:props="defaultProps"
:expand-on-click-node="false"
show-checkbox
node-key="catId"
:default-expanded-keys="expandedKey"
:draggable="draggable"
:allow-drop="allowDrop"
@node-drop="handleDrop"
ref="menuTree"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button
v-if="node.level <=2"
type="text"
size="mini"
@click="() => append(data)"
>Append</el-button>
<el-button type="text" size="mini" @click="edit(data)">edit</el-button>
<el-button
v-if="node.childNodes.length==0"
type="text"
size="mini"
@click="() => remove(node, data)"
>Delete</el-button>
</span>
</span>
</el-tree>
<el-dialog
:title="title"
:visible.sync="dialogVisible"
width="30%"
:close-on-click-modal="false"
>
<el-form :model="category">
<el-form-item label="分类名称">
<el-input v-model="category.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="图标">
<el-input v-model="category.icon" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="计量单位">
<el-input v-model="category.productUnit" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submitData">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';
export default {
//import引入的组件需要注入到对象中才能使用
components: {},
props: {},
data() {
return {
pCid: [],
draggable: false,
updateNodes: [],
maxLevel: 0,
title: "",
dialogType: "", //edit,add
category: {
name: "",
parentCid: 0,
catLevel: 0,
showStatus: 1,
sort: 0,
productUnit: "",
icon: "",
catId: null
},
dialogVisible: false,
menus: [],
expandedKey: [],
defaultProps: {
children: "children",
label: "name"
}
};
},
//计算属性 类似于data概念
computed: {},
//监控data中的数据变化
watch: {},
//方法集合
methods: {
getMenus() {
this.$http({
url: this.$http.adornUrl("/product/category/list/tree"),
method: "get"
}).then(({ data }) => {
console.log("成功获取到菜单数据...", data.data);
this.menus = data.data;
});
},
batchDelete() {
let catIds = [];
let checkedNodes = this.$refs.menuTree.getCheckedNodes();
console.log("被选中的元素", checkedNodes);
for (let i = 0; i < checkedNodes.length; i++) {
catIds.push(checkedNodes[i].catId);
}
this.$confirm(`是否批量删除【${catIds}】菜单?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$http({
url: this.$http.adornUrl("/product/category/delete"),
method: "post",
data: this.$http.adornData(catIds, false)
}).then(({ data }) => {
this.$message({
message: "菜单批量删除成功",
type: "success"
});
this.getMenus();
});
})
.catch(() => {});
},
batchSave() {
this.$http({
url: this.$http.adornUrl("/product/category/update/sort"),
method: "post",
data: this.$http.adornData(this.updateNodes, false)
}).then(({ data }) => {
this.$message({
message: "菜单顺序等修改成功",
type: "success"
});
//刷新出新的菜单
this.getMenus();
//设置需要默认展开的菜单
this.expandedKey = this.pCid;
this.updateNodes = [];
this.maxLevel = 0;
// this.pCid = 0;
});
},
handleDrop(draggingNode, dropNode, dropType, ev) {
console.log("handleDrop: ", draggingNode, dropNode, dropType);
//1、当前节点最新的父节点id
let pCid = 0;
let siblings = null;
if (dropType == "before" || dropType == "after") {
pCid =
dropNode.parent.data.catId == undefined
? 0
: dropNode.parent.data.catId;
siblings = dropNode.parent.childNodes;
} else {
pCid = dropNode.data.catId;
siblings = dropNode.childNodes;
}
this.pCid.push(pCid);
//2、当前拖拽节点的最新顺序,
for (let i = 0; i < siblings.length; i++) {
if (siblings[i].data.catId == draggingNode.data.catId) {
//如果遍历的是当前正在拖拽的节点
let catLevel = draggingNode.level;
if (siblings[i].level != draggingNode.level) {
//当前节点的层级发生变化
catLevel = siblings[i].level;
//修改他子节点的层级
this.updateChildNodeLevel(siblings[i]);
}
this.updateNodes.push({
catId: siblings[i].data.catId,
sort: i,
parentCid: pCid,
catLevel: catLevel
});
} else {
this.updateNodes.push({ catId: siblings[i].data.catId, sort: i });
}
}
//3、当前拖拽节点的最新层级
console.log("updateNodes", this.updateNodes);
},
updateChildNodeLevel(node) {
if (node.childNodes.length > 0) {
for (let i = 0; i < node.childNodes.length; i++) {
var cNode = node.childNodes[i].data;
this.updateNodes.push({
catId: cNode.catId,
catLevel: node.childNodes[i].level
});
this.updateChildNodeLevel(node.childNodes[i]);
}
}
},
allowDrop(draggingNode, dropNode, type) {
//1、被拖动的当前节点以及所在的父节点总层数不能大于3
//1)、被拖动的当前节点总层数
console.log("allowDrop:", draggingNode, dropNode, type);
//
this.countNodeLevel(draggingNode);
//当前正在拖动的节点+父节点所在的深度不大于3即可
let deep = Math.abs(this.maxLevel - draggingNode.level) + 1;
console.log("深度:", deep);
// this.maxLevel
if (type == "inner") {
// console.log(
// `this.maxLevel:${this.maxLevel};draggingNode.data.catLevel:${draggingNode.data.catLevel};dropNode.level:${dropNode.level}`
// );
return deep + dropNode.level <= 3;
} else {
return deep + dropNode.parent.level <= 3;
}
},
countNodeLevel(node) {
//找到所有子节点,求出最大深度
if (node.childNodes != null && node.childNodes.length > 0) {
for (let i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].level > this.maxLevel) {
this.maxLevel = node.childNodes[i].level;
}
this.countNodeLevel(node.childNodes[i]);
}
}
},
edit(data) {
console.log("要修改的数据", data);
this.dialogType = "edit";
this.title = "修改分类";
this.dialogVisible = true;
//发送请求获取当前节点最新的数据
this.$http({
url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
method: "get"
}).then(({ data }) => {
//请求成功
console.log("要回显的数据", data);
this.category.name = data.data.name;
this.category.catId = data.data.catId;
this.category.icon = data.data.icon;
this.category.productUnit = data.data.productUnit;
this.category.parentCid = data.data.parentCid;
this.category.catLevel = data.data.catLevel;
this.category.sort = data.data.sort;
this.category.showStatus = data.data.showStatus;
/**
* parentCid: 0,
catLevel: 0,
showStatus: 1,
sort: 0,
*/
});
},
append(data) {
console.log("append", data);
this.dialogType = "add";
this.title = "添加分类";
this.dialogVisible = true;
this.category.parentCid = data.catId;
this.category.catLevel = data.catLevel * 1 + 1;
this.category.catId = null;
this.category.name = "";
this.category.icon = "";
this.category.productUnit = "";
this.category.sort = 0;
this.category.showStatus = 1;
},
submitData() {
if (this.dialogType == "add") {
this.addCategory();
}
if (this.dialogType == "edit") {
this.editCategory();
}
},
//修改三级分类数据
editCategory() {
var { catId, name, icon, productUnit } = this.category;
this.$http({
url: this.$http.adornUrl("/product/category/update"),
method: "post",
data: this.$http.adornData({ catId, name, icon, productUnit }, false)
}).then(({ data }) => {
this.$message({
message: "菜单修改成功",
type: "success"
});
//关闭对话框
this.dialogVisible = false;
//刷新出新的菜单
this.getMenus();
//设置需要默认展开的菜单
this.expandedKey = [this.category.parentCid];
});
},
//添加三级分类
addCategory() {
console.log("提交的三级分类数据", this.category);
this.$http({
url: this.$http.adornUrl("/product/category/save"),
method: "post",
data: this.$http.adornData(this.category, false)
}).then(({ data }) => {
this.$message({
message: "菜单保存成功",
type: "success"
});
//关闭对话框
this.dialogVisible = false;
//刷新出新的菜单
this.getMenus();
//设置需要默认展开的菜单
this.expandedKey = [this.category.parentCid];
});
},
remove(node, data) {
var ids = [data.catId];
this.$confirm(`是否删除【${data.name}】菜单?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$http({
url: this.$http.adornUrl("/product/category/delete"),
method: "post",
data: this.$http.adornData(ids, false)
}).then(({ data }) => {
this.$message({
message: "菜单删除成功",
type: "success"
});
//刷新出新的菜单
this.getMenus();
//设置需要默认展开的菜单
this.expandedKey = [node.parent.data.catId];
});
})
.catch(() => {});
console.log("remove", node, data);
}
},
//生命周期 - 创建完成(可以访问当前this实例)
created() {
this.getMenus();
},
//生命周期 - 挂载完成(可以访问DOM元素)
mounted() {},
beforeCreate() {}, //生命周期 - 创建之前
beforeMount() {}, //生命周期 - 挂载之前
beforeUpdate() {}, //生命周期 - 更新之前
updated() {}, //生命周期 - 更新之后
beforeDestroy() {}, //生命周期 - 销毁之前
destroyed() {}, //生命周期 - 销毁完成
activated() {} //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style scoped>
</style>
7.2后端代码
package com.atguigu.gulimall.product.controller; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import com.atguigu.gulimall.product.entity.CategoryEntity; import com.atguigu.gulimall.product.service.CategoryService; import com.atguigu.common.utils.PageUtils; import com.atguigu.common.utils.R; import javax.validation.Valid; /** * 商品三级分类 * * @author leifengyang * @email leifengyang@gmail.com * @date 2019-10-01 22:50:32 */ @RestController @RequestMapping("product/category") public class CategoryController { @Autowired private CategoryService categoryService; /** * 查出所有分类以及子分类,以树形结构组装起来 */ @RequestMapping("/list/tree") public R list(){ List<CategoryEntity> entities = categoryService.listWithTree(); return R.ok().put("data", entities); } /** * 信息 */ @RequestMapping("/info/{catId}") //@RequiresPermissions("product:category:info") public R info(@PathVariable("catId") Long catId){ CategoryEntity category = categoryService.getById(catId); return R.ok().put("data", category); } /** * 保存 */ @RequestMapping("/save") //@RequiresPermissions("product:category:save") public R save(@RequestBody CategoryEntity category){ categoryService.save(category); return R.ok(); } @RequestMapping("/update/sort") //@RequiresPermissions("product:category:update") public R updateSort(@RequestBody CategoryEntity[] category){ categoryService.updateBatchById(Arrays.asList(category)); return R.ok(); } /** * 修改 */ @RequestMapping("/update") //@RequiresPermissions("product:category:update") public R update(@RequestBody CategoryEntity category){ categoryService.updateCascade(category); return R.ok(); } /** * 删除 * @RequestBody:获取请求体,必须发送POST请求 * SpringMVC自动将请求体的数据(json),转为对应的对象 */ @RequestMapping("/delete") //@RequiresPermissions("product:category:delete") public R delete(@RequestBody Long[] catIds){ //categoryService.removeByIds(Arrays.asList(catIds)); categoryService.removeMenuByIds(Arrays.asList(catIds)); return R.ok(); } }
package com.atguigu.gulimall.product.service.impl; import com.atguigu.gulimall.product.service.CategoryBrandRelationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.atguigu.common.utils.PageUtils; import com.atguigu.common.utils.Query; import com.atguigu.gulimall.product.dao.CategoryDao; import com.atguigu.gulimall.product.entity.CategoryEntity; import com.atguigu.gulimall.product.service.CategoryService; import org.springframework.transaction.annotation.Transactional; @Service("categoryService") public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService { // @Autowired // CategoryDao categoryDao; @Autowired CategoryBrandRelationService categoryBrandRelationService; @Override public PageUtils queryPage(Map<String, Object> params) { IPage<CategoryEntity> page = this.page( new Query<CategoryEntity>().getPage(params), new QueryWrapper<CategoryEntity>() ); return new PageUtils(page); } @Override public List<CategoryEntity> listWithTree() { //1、查出所有分类 List<CategoryEntity> entities = baseMapper.selectList(null); //2、组装成父子的树形结构 //2.1)、找到所有的一级分类 List<CategoryEntity> level1Menus = entities.stream().filter(categoryEntity -> categoryEntity.getParentCid() == 0 ).map((menu)->{ menu.setChildren(getChildrens(menu,entities)); return menu; }).sorted((menu1,menu2)->{ return (menu1.getSort()==null?0:menu1.getSort()) - (menu2.getSort()==null?0:menu2.getSort()); }).collect(Collectors.toList()); return level1Menus; } @Override public void removeMenuByIds(List<Long> asList) { //TODO 1、检查当前删除的菜单,是否被别的地方引用 //逻辑删除 baseMapper.deleteBatchIds(asList); } //[2,25,225] @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()]); } /** * 级联更新所有关联的数据 * @param category */ @Transactional @Override public void updateCascade(CategoryEntity category) { this.updateById(category); categoryBrandRelationService.updateCategory(category.getCatId(),category.getName()); } //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; } //递归查找所有菜单的子菜单 private List<CategoryEntity> getChildrens(CategoryEntity root,List<CategoryEntity> all){ List<CategoryEntity> children = all.stream().filter(categoryEntity -> { return categoryEntity.getParentCid() == root.getCatId(); }).map(categoryEntity -> { //1、找到子菜单 categoryEntity.setChildren(getChildrens(categoryEntity,all)); return categoryEntity; }).sorted((menu1,menu2)->{ //2、菜单的排序 return (menu1.getSort()==null?0:menu1.getSort()) - (menu2.getSort()==null?0:menu2.getSort()); }).collect(Collectors.toList()); return children; } }
浙公网安备 33010602011771号