谷粒商城之商品服务-三级分类(展示与删除)

目录

三级类目查询后台代码实现

后台管理系统的菜单创建

配置网关和路径重写

网关统一配置跨域

三级类目后台管理系统的页面显示

三级分类删除页面效果的编写 

​ 三级分类逻辑删除后台实现

三级类目删除功能的前后联调


三级类目查询后台代码实现

catagory表的表结构,首先一级类目的parent_cid为0,二级类目以及三级类目的parent_cid为cid,sort字段用于排序

 baseMapper等价于catagoryDao

代码实现:

 /**
     * 三级分类查询,以树状结构呈现
     * @return
     */
    @Override
    public List<CategoryEntity> listWithTree() {
        // 1.查询所有商品类目
        List<CategoryEntity> all=categoryDao.selectList(null);
        // 2.1、查询一级类目
        List<CategoryEntity> categoryEntities= all.stream().filter(menu1->{
                   return menu1.getParentCid().equals(0L);
                }
          // 刷选出一级分类
        ).map((menu1)->{
            menu1.setChildren(getChilren(menu1,all));
            return menu1;
        }).sorted((item1,item2)->{
            // 排序
            return (item1.getSort()==null?0:item1.getSort())-(item2.getSort()==null?0:item2.getSort());
        }).collect(Collectors.toList());
        return categoryEntities;
    }

    /**
     *  查询子节点
     * @param menu1
     * @param all
     * @return
     */
    private List<CategoryEntity> getChilren(CategoryEntity menu1, List<CategoryEntity> all) {
        List<CategoryEntity> chilrenList= all.stream().filter(chilrenMenu->
            chilrenMenu.getParentCid().equals(menu1.getCatId())
            // 查询子节点
        ).map((chilrenMenu)->{
            chilrenMenu.setChildren(getChilren(chilrenMenu,all));
            return chilrenMenu;
        }).sorted((item1,item2)->{
            return (item1.getSort()==null?0:item1.getSort())-(item2.getSort()==null?0:item2.getSort());
        }).collect(Collectors.toList());
        return  chilrenList;
    }

后台管理系统的菜单创建

①创建一个商品系统(一级菜单)目录

 

 

②在商品菜单目录下创建一个分类维护菜单

菜单路由讲解 

当我们点击角色管理时,就会发送一个sys-role的请求,角色管理的菜单路由是sys/role,说明会将sys/role转化成sys-role

实际上访问sys-role就是请求sys文件夹下的role.vue

③分类维护的菜单路由为product/category,所以在views中的modules下面创建一个product文件,在product文件夹中创建category.vue

④编写category.vue请求后台数据

参考role.vue的请求数据方法,对category.vue进行编写

访问的是 http://localhost:8080/renren-fast/product/category/list/tree 

而我们想要访问的路径是 http://localhost:10000/product/category/list/tree

我们应该将请求统一发送给网关,由网关根据我们的请求路径进行相应路由

配置网关和路径重写

①renren-fast服务注册到网关中

出现问题

java: You aren't using a compiler supported by lombok, so lombok will not work and has been disabled

解决方案:You aren‘t using a compiler supported by lombok, so lombok will not work and has been disabled._小魔王博客-CSDN博客

出现问题:

The following method did not exist:

    com.google.common.collect.Sets$SetView.iterator()Lcom/google/common/collect/UnmodifiableIterator;

The method's class, com.google.common.collect.Sets$SetView, is available from the following locations:

    jar:file:/D:/MavenRepository/com/google/guava/guava/18.0/guava-18.0.jar!/com/google/common/collect/Sets$SetView.class

It was loaded from the following location:

    file:/D:/MavenRepository/com/google/guava/guava/18.0/guava-18.0.jar

出现原因是:guava-18跟别的jar有冲突,要么将guava的版本升级要么降级

renren-fast成功注册到nacos中

index.js中配置访问的路径

 将其改成访问网关的路径,并且都带上api

路由重写

 网关路由配置:

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
        - id: admin_route
          uri: lb://renren-fast  # lb:负载均衡
          predicates:
            - Path=/api/**      # 路径中带有api的所有请求的都路由
          filters:
            - RewritePath=/api/?(?<segment>.*),/renren-fast/$\{segment}
  application:
    name: gulimall-gateway
server:
  port: 88

出现CROS错误:

Access to XMLHttpRequest at 'http://localhost:88/api/sys/menu/nav?t=1639023916234' 
from origin 'http://localhost:8001' has been blocked by CORS policy: Response to 
preflight request doesn't pass access control 
check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

出现原因:当我们想从'http://localhost:8001'访问'http://localhost:88',这个两个ip地址不是在同一个域下的,所以出现了跨域访问问题。'Access-Control-Allow-Origin' header这个请求头不在访问的资源中,解决方案需:要设置允许跨域的请求头

网关统一配置跨域

解决方案: 

gateway中编写配置类:所有请求从网关返回的时候都会带上运行跨域访问的请求头

@Configuration
public class GulimallCROSConfig {
    @Bean
    public CorsWebFilter corsWebFilter(){
        UrlBasedCorsConfigurationSource corsConfigurationSource=new UrlBasedCorsConfigurationSource();

        CorsConfiguration corsConfiguration=new CorsConfiguration();
        // 跨域设置
        corsConfiguration.addAllowedHeader("*");  //配置那些请求头可以跨域访问
        corsConfiguration.addAllowedMethod("*"); //配置那些方法可以跨域访问
        corsConfiguration.addAllowedOrigin("*"); //配置那些来源可以跨域访问
        corsConfiguration.setAllowCredentials(true); //配置跨域请求可以携带cookie
        corsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration);

        return new CorsWebFilter(corsConfigurationSource);
    }
}

出现问题:

Access to XMLHttpRequest at 'http://localhost:88/api/sys/login' from origin 'http://localhost:8001' has been blocked by CORS policy: The 'Access-Control
-Allow-Origin' header contains multiplevalues'http://localhost:8001,http://localhost:8001', but only one is allowed.

允许跨域的请求头被设置了两个,只允许一个

出现问题的原因:renren-fast中的也设置了允许跨域的配置

解决方案:将renren-fast中的允许跨域配置类注释

 

三级类目后台管理系统的页面显示

经过网关后,请求路径变成了:http://localhost:88/renrenfast/product/category/list/tree

我们想要让请求路径变成:http://localhost:10000/product/category/list/tree

因此,需要编写路由:

 

出现问题:访问不到

出现问题的原因是:admin_router中的断言会优先将路径进行重写

解决方案:断言中小范围的路径访问要写在大范围的路径访问之前

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
        - id: product_route
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**
          filters:
            - RewritePath=/api/?(?<segment>.*),/$\{segment}
            
        - id: admin_route
          uri: lb://renren-fast  # lb:负载均衡
          predicates:
            - Path=/api/**      # 路径中带有api的所有请求的都路由
          filters:
            - RewritePath=/api/?(?<segment>.*),/renren-fast/$\{segment}

  application:
    name: gulimall-gateway
server:
  port: 88

将获取到data在控制台中打印,发现data中的data才是真正的存放数据的对象

<template>
  <el-tree :data="menu" :props="defaultProps" ></el-tree>
</template>

<script>
export default {
 data() {
    //这里存放数据
    return {
      menu: [],
      defaultProps: {
          children: 'children',  //封装子节点,prop会自动进行一个遍历
          label: 'name'  //显示数据,prop会自动进行一个遍历
        }
    };
  },
 methods: {
    //获取数据
    getDataList() {
      this.dataListLoading = true;
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get",
      }).then(({data}) => {  // 1.使用解构即{},将data对象解构出来
            // 2.将data中的data赋值给menu
            this.menu=data.data;
            // 3.将data中的data对象的属性children和name赋值给defaultProps中的children和label
      });
    },
  },
 created() {
      //模板一旦被创建就被加载
      this.getDataList();
  },
};

三级分类删除页面效果的编写 

我们使用scoped slot编写添加和删除按键

 

补上复选框

  

补全append和remove方法,并打印看看data和node

出现的问题:当我们点击append或者delete时,会自动进行一个扩展,我们想要的效果是只有当我们点击箭头才进行扩展

解决方案:

出现问题:只有节点没有子节点是才能进行delete,只有一级和二级目录才能append

解决方案:使用v-if进行一个判断,首先使用scoped slot会传进来node和data两个数据,其中node有个level属性,就是节点的层级,node还有个childNodes表示子节点的个数即childNodes数组的长度为0可以删除

出现问题:我们需要为Tree设置node-key,方便标识每个节点

解决方案:catId是每个节点唯一的标识属性

 

 三级分类逻辑删除后台实现

①TODO的使用,相当于备用录,用于提醒还未实现的步骤或功能

②alt+enter:快速创建方法

 

 使用postman进行测试:

 

这是一个真正的物理删除,在实际开发中并不常用,一般使用逻辑删除

mybatis-plus逻辑删除指南地址:逻辑删除 | MyBatis-Plus

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
private Integer deleted;

 说明一下:我使用的是mybatis-plus 3.2版本的没有这个logic-delete-field配置项并不影响使用

出现问题:showStatus属性1代表显示,0代表不显示与我们的逻辑删除配置刚好相反

解决方案:@TableLogic中有两个属性值,可以重新设置逻辑删除的值

日志打印:gulimall包下的都会打印日志

三级类目删除功能的前后联调

在httpRequest.js中url的拼接规则

当我们点击Delete按键就会去调用remove方法,因此需要去重写remove方法

重写remove方法: 

出现问题:页面没有即时更新

解决方案:删除成功之后再次调用获取数据方法,进行一个数据的更新

 出现问题:1.没有删除确认提示 2.删除成功或失败应该有消息提示 3.删除成功或失败应该父节点应该扩展而不是整个层级合并

  

<template>
  <!-- 使用v-bind/':'才能为属性赋值成功 -->
  <div>
    <el-tree
    show-checkbox
    :data="menu"
    :props="defaultProps"
    :expand-on-click-node="false"
    node-key="catId"
    :default-expanded-keys="expandKey"
  >
    <span class="custom-tree-node" slot-scope="{ node, data }">
      <span>{{ node.label }}</span>
      <span>
        <!--箭头函数调用append方法-->
        <!-- 一级目录和二级目录才允许append -->
        <el-button
          v-if="node.level <= 2"
          type="text"
          size="mini"
          @click="() => append(data)"
        >
          Append
        </el-button>
        <!-- 没有子节点才允许delete -->
        <el-button
          v-if="node.childNodes.length == 0"
          type="text"
          size="mini"
          @click="() => remove(node, data)"
        >
          Delete
        </el-button>
      </span>
    </span>
  </el-tree>
  </div>
</template>
<script>
export default {
  data() {
    //这里存放数据
    return {
      menu: [],
      expandKey: [],
      defaultProps: {
        children: "children", //封装子节点,prop会自动进行一个遍历
        label: "name", //显示数据,prop会自动进行一个遍历
      },
    };
  },
 methods: {
    //获取数据
    getDataList() {
      this.dataListLoading = true;
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get",
      }).then(({ data }) => {
        // 1.使用解构即{},将data对象解构出来
        // 2.将data中的data赋值给menu
        this.menu = data.data;
        // 3.将data中的data对象的属性children和name赋值给defaultProps中的children和label
      });
    },
    append(data) {
      console.log("append", data);
    },

    remove(node, data) {
      let catId = [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(catId, false),
          }).then(({ data }) => {
            this.$message({
              type: "success",
              message: "删除成功!",
            });
            // 刷新菜单
            this.getDataList();
            // 默认菜单展示
            this.expandKey = [node.parent.data.catId];
          });
        })
        .catch(() => {
          this.$message({
            type: "info",
            message: "已取消删除",
          });
        });
      console.log("remove", node, data);
    },
  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
    //模板一旦被创建就被加载
    this.getDataList();
  },
};

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值