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后端代码
1.2.1给后端renrenfast 添加网关依赖进行配置
<dependency> <groupId>com.atguigu.gulimall</groupId> <artifactId>gulimall-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
1.2.2网关配置
cloud: nacos: server-addr: 127.0.0.1:8848 application: name: renren-fast
1.2.3开启注册服务发现功能
在启动项加上@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 [email protected] * @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; } }
标签:category,菜单,http,catId,--,谷粒,import,data,商城 From: https://www.cnblogs.com/ai377377/p/17412217.html