尚硅谷谷粒商城项目学习笔记-商品服务-P3-三级分类
创始人
2024-03-30 10:41:39
0

商品服务-P3-三级分类

  • 0.三级分类示例
    • 0.1涉及数据库表
  • 1.三级分类-查询
    • 1.0后端代码实现-微服务Product
    • 1.1前端代码
      • 1.1.1创建category页面代码
      • 1.1.2修改请求根路径到网关
    • 1.2后端代码
      • 1.2.1给后端renrenfast 添加网关依赖进行配置
      • 1.2.2网关配置
      • 1.2.3项目启动出现问题参照
      • 1.2.4开启注册服务发现功能
      • 1.2.5人人fast请求给网关
      • 1.2.6配置Nacos-product
  • 2.解决跨域问题
    • 2.1使用Nginx部署为同一域
    • 2.2配置当次请求允许跨域-自定义filter
  • 3.三级分类-删除菜单
    • 3.1前端代码
      • 3.1.1页面代码
      • 3.1.2发送POST请求模板
      • 3.1.3发送get请求模板
      • 3.1.4删除代码
    • 3.2后端代码
      • 3.2.1逻辑删除
  • 4.三级分类-添加子菜单
    • 4.2前端代码
    • 4.3后端代码
  • 5.三级分类-修改
    • 5.1前端代码
    • 5.2后端代码
  • 6.三级分类-拖拽节点修改父子关系
    • 6.1 前端代码
    • 6.2后端代码
  • 7.整体设计
    • 7.1前端代码
    • 7.2后端代码

0.三级分类示例

在这里插入图片描述

0.1涉及数据库表

在这里插入图片描述

1.三级分类-查询

在这里插入图片描述

1.0后端代码实现-微服务Product

package com.jq.gulimall.gulimallproduct.service.impl;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;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.jq.common.utils.PageUtils;
import com.jq.common.utils.Query;import com.jq.gulimall.gulimallproduct.dao.CategoryDao;
import com.jq.gulimall.gulimallproduct.entity.CategoryEntity;
import com.jq.gulimall.gulimallproduct.service.CategoryService;@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl implements CategoryService {@Overridepublic PageUtils queryPage(Map params) {IPage page = this.page(new Query().getPage(params),new QueryWrapper());return new PageUtils(page);}@Overridepublic List listWithTree() {/**** 1.查出所有分类* 2.组装成父子的树形结构*///1.查询所有分类List entities = baseMapper.selectList(null);//2.组装父子结构List 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找到所有的一级分类 根据parentIDreturn level1Menus;}/*** 递归查找所有菜单的子菜单* @param root 当前菜单* @param all 所有菜单* @return*/private ListgetChildrens(CategoryEntity root,List all){List 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前端代码

1.1.1创建category页面代码


1.1.2修改请求根路径到网关

在这里插入图片描述

1.2后端代码

1.2.1给后端renrenfast 添加网关依赖进行配置

	com.jq.gulishangchenggulimall-common1.0-SNAPSHOT

1.2.2网关配置

  cloud:nacos:server-addr: 127.0.0.1:8848	application:name: renren-fast

1.2.3项目启动出现问题参照

https://blog.csdn.net/little___ant/article/details/126885567

1.2.4开启注册服务发现功能

/*** Copyright (c) 2016-2019 人人开源 All rights reserved.** https://www.renren.io** 版权所有,侵权必究!*/package io.renren;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDiscoveryClient
@SpringBootApplication
public class RenrenApplication {public static void main(String[] args) {SpringApplication.run(RenrenApplication.class, args);}}

1.2.5人人fast请求给网关

根据请求路径重写路由规则
在这里插入图片描述

  • Path=/api/gulimallproduct/**
  • 天坑当时包不是product 结果以下路径就不可以
  • - Path=/api/product/**
spring:cloud:gateway:routes:- id : product_routeuri: lb://gulimall-productpredicates:- Path=/api/gulimallproduct/**filters:- RewritePath=/api/(?.*),/$\{segment}- id: admin_routeuri: lb://renren-fastpredicates:- Path=/api/**filters:- RewritePath=/api/(?.*),/renren-fast/$\{segment}

1.2.6配置Nacos-product

spring.application.name=gulimall-productspring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=0d91cee2-1d01-4999-80c4-6b2650d8d29e
spring:datasource:username: rootpassword: rooturl: jdbc:mysql://192.168.56.10:3306/gulimall_pms?useUnicode=true&characterEncoding=utf8&useSSL=falsedriver-class-name: com.mysql.cj.jdbc.Driverapplication:name: gulimall-productcloud:nacos:discovery:server-addr: 127.0.0.1:8848
mybatis-plus:mapper-locations: classpath*:/mapper/**/*.xmlglobal-config:db-config:id-type: autoserver:port: 10000

2.解决跨域问题

在这里插入图片描述

2.1使用Nginx部署为同一域

在这里插入图片描述

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

  • Access-Control-Allow-Origin:支持哪些来源的请求跨域
  • Access-Control-Allow-Methods:支持哪些方法跨域
  • Access-Control-Allow-Credentials:跨域请求默认不包含cookie,设置为true可以包含cookie
  • Access-Control-Expose-Headers:跨域请求暴露的字段
  • CORS请求时,XMLHttpRequest对象getResponseHeader()方法只能拿到6个基本字段:
    Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
  • Access-Control-Max-Age:表明该响应的有效时间为多少秒。在有效时间内,浏览器无须为同一请求再次发起预检请求。请注意,浏览器自身维护了一个最大有效时间,如果该首部字段的值超过了最大有效时间,将不会生效。
package com.jq.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.CorsConfigurationSource;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.server.ServerWebExchange;@Configuration
public class GulimallCorsConfiguration {@Beanpublic CorsWebFilter corsWebFilter(){UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration corsConfiguration = new CorsConfiguration();//配置跨域corsConfiguration.addAllowedHeader("*");corsConfiguration.addAllowedMethod("*");corsConfiguration.addAllowedOrigin("*");corsConfiguration.setAllowCredentials(true);source.registerCorsConfiguration("/**",corsConfiguration);return new CorsWebFilter(source);}
}

3.三级分类-删除菜单

在这里插入图片描述在这里插入图片描述

3.1前端代码

3.1.1页面代码


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.三级分类-修改

在这里插入图片描述

5.1前端代码

//修改三级分类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.三级分类-拖拽节点修改父子关系

在这里插入图片描述

6.1 前端代码

    //拖拽修改父子关系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);//当前节点最新的父节点idlet 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前端代码


7.2后端代码

package com.jq.gulimall.product.controller;import java.util.Arrays;
import java.util.List;//import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.jq.gulimall.product.entity.CategoryEntity;
import com.jq.gulimall.product.service.CategoryService;
import com.jq.common.utils.R;/*** 商品三级分类** @author cjq* @email ${email}* @date 2022-10-13 21:46:13*/
@RestController
@RequestMapping("product/category")
public class CategoryController {@Autowiredprivate CategoryService categoryService;/*** 列表* 查出所有分类以及子分类,以树形结构组装起来*/@RequestMapping("/list/tree")public R list(){Listentities=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.updateById(category);return R.ok();}/*** 删除* @RequestBody :获取请求体,必须发送post请求* SpringMVC 自动将请求体(JSON)数据转换成对象*/@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();}}
package com.jq.gulimall.product.service.impl;import org.springframework.stereotype.Service;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.jq.common.utils.PageUtils;
import com.jq.common.utils.Query;import com.jq.gulimall.product.dao.CategoryDao;
import com.jq.gulimall.product.entity.CategoryEntity;
import com.jq.gulimall.product.service.CategoryService;@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl implements CategoryService {@Overridepublic PageUtils queryPage(Map params) {IPage page = this.page(new Query().getPage(params),new QueryWrapper());return new PageUtils(page);}@Overridepublic List listWithTree() {/**** 1.查出所有分类* 2.组装成父子的树形结构*///1.查询所有分类List entities = baseMapper.selectList(null);//2.组装父子结构List 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找到所有的一级分类 根据parentIDreturn level1Menus;}@Overridepublic void removeMenuByIds(List asList) {//TODO 1.检测当前删除的菜单是否被别的地方引用/**** 逻辑删除:参照mybatisPlus官网* 1.配置全局的逻辑删除规则* 2: 实体类字段上加上@TableLogic注解** 	 * 是否显示[0-不显示,1显示]*  @TableLogic(value = "1",delval = "0")* 	private Integer showStatus;***/baseMapper.deleteBatchIds(asList);}/*** 递归查找所有菜单的子菜单* @param root 当前菜单* @param all 所有菜单* @return*/private ListgetChildrens(CategoryEntity root,List all){List 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;}}

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...