三级分类及配置网关(后台管理)

三级分类

分类表
在这里插入图片描述
在 CategoryController 中编写查询分类方法

    /**
     * 查出所有分类以及子分类,以树形结构组装起来
     */
    @RequestMapping("/list/tree")
    //@RequiresPermissions("product:category:list")
    public R list(){
        List<CategoryEntity> entities = categoryService.listWithTree();
        return R.ok().put("data", entities);
    }

CategoryEntity 实体类中加上 children 字段,表示所有的子分类

	// 表示所有的子分类,由于这个字段不在数据表里面所以加上 exist=false
	@TableField(exist=false)
	private List<CategoryEntity> children;

创建 service 接口方法和 Impl 实现类

List<CategoryEntity> listWithTree();
    @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 // 一级分类的 ParentCid 是 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()); // 排完序后收集到 level1Menus 中
        return level1Menus;
    }

    // 递归查找所有菜单的子菜单
    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;
    }

在这里遇到了一个端口冲突的 bug,解决方法https://blog.csdn.net/zzxwefxf/article/details/82048057

后端启动 renren-fast,前端启动:npm run dev,在启动 product 模块,nacos 也要启动

views 下 moudules 下新建 category.vue

<!--  -->
<template>
  <el-tree
    :data="data"
    :props="defaultProps"
    @node-click="handleNodeClick"
  ></el-tree>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';

export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},

  //监听属性 类似于data概念
  computed: {},
  //监控data中的数据变化
  watch: {},
  data: [], // 真正的数据从后台发送请求获取
  methods: {
    // 获取数据列表
      getMenus () {
        this.$http({
          url: this.$http.adornUrl('/product/category/list/tree'),
          method: 'get'

        }).then(data=>{
            console.log("获取到数据",data);
        })
      },
  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
      this.getMenus();
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {},
  beforeCreate() {}, //生命周期 - 创建之前
  beforeMount() {}, //生命周期 - 挂载之前
  beforeUpdate() {}, //生命周期 - 更新之前
  updated() {}, //生命周期 - 更新之后
  beforeDestroy() {}, //生命周期 - 销毁之前
  destroyed() {}, //生命周期 - 销毁完成
  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style scoped>
</style>

浏览器输入 http://localhost:8001/#/product-category 测试是否可以获取到数据,控制台 404 请求
在这里插入图片描述

配置网关

要开始配置网关了,前端配置文件中配置网关地址
在这里插入图片描述

后端将 renren-fast 中配置到注册中心中(引入 common 模块,配置 yml,添加启动类注解)

配置 gateway 模块

spring:
  cloud:
    gateway:
      routes:
        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**

目前这种配置登录的时候验证码还是会获取不到的
在这里插入图片描述
这个请求效果还是 404 的,因为满足断言规则网关找到注册中心中的 renren-fast 后,会转到这里:http://renren-fast:8080/api/captcha.jpg。但是 renren-fast 默认请求是从 localhost:8080/renren-fast/captcha.jpg 中获取

这怎么办呢?

这时候可以使用网关的路径重写,springcloud 官网中找到
在这里插入图片描述

spring:
  cloud:
    gateway:
      routes:
        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}

只要发送 api 下的任意请求,默认先路由到后台管理系统 renren-fast(uri: lb://renren-fast),并且重写成指定路径

这里图片我报了 503 错误,看了弹幕说是网关没注册到注册中心,果然我的网关没有注册到 nacos

但是登录还是报错,跨域
在这里插入图片描述
跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是
浏览器对 javascript 施加的安全限制。

同源策略:是指协议,域名,端口都要相同,其中有一个不同都会产生跨域
在这里插入图片描述
跨域流程
在这里插入图片描述
解决跨域

gateway 模块新建 config 包下 GulimallCorsConfiguration 配置类

@Configuration
public class GulimallCorsConfiguration {

    @Bean
    public 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);
    }

}

注释掉 renren-fast 自带跨域配置类,要不然会报错
在这里插入图片描述
登录问题解决,但是分类菜单数据并没有出来
在这里插入图片描述
因为网关现在默认是把所有的请求转给 renren-fast 的,但其实这个请求应该转给 product,在 gateway 模块中配置网关

        - id: product_route
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}

在 product 的 bootstrap.yml 中添加配置,nacos 中新建命名空间

  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        namespace:
  application:
    name: gulimall-product

在这里插入图片描述
将 product 注册到 nacos,bootstrap.yml 添加配置,这样网关就能实时的发现 product 服务然后负载均衡路由到这

  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
      config:
        server-addr: 127.0.0.1:8848
        namespace: 898bc93f-e8e9-4709-9b05-10e101ab8358
  application:
    name: gulimall-product

浏览器地址栏输入:http://localhost:88/api/product/category/list/tree 报错
在这里插入图片描述
由于网关配置中路由到 renren-fast 中的断言 - Path=/api/** 先生效了,我们的请求被它路由走了,所以调整以下路由顺序,把精确匹配 product 的放在上面
在这里插入图片描述
再次测试,正常执行

前端页面

这样就可以要到数据了,然后我们要在页面上显示出来,开始写前端 category.vue 了

<!--  -->
<template>
  <el-tree 
    :data="menus"
    :props="defaultProps"
    @node-click="handleNodeClick"
  ></el-tree>
</template>

<script>
//这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
//例如:import 《组件名称》 from '《组件路径》';

export default {
  //import引入的组件需要注入到对象中才能使用
  components: {},
  props: {},
  data() {
      return {
          menus: [],
          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;
        })
      },
  },
  //生命周期 - 创建完成(可以访问当前this实例)
  created() {
      this.getMenus();
  },
  //生命周期 - 挂载完成(可以访问DOM元素)
  mounted() {},
  beforeCreate() {}, //生命周期 - 创建之前
  beforeMount() {}, //生命周期 - 挂载之前
  beforeUpdate() {}, //生命周期 - 更新之前
  updated() {}, //生命周期 - 更新之后
  beforeDestroy() {}, //生命周期 - 销毁之前
  destroyed() {}, //生命周期 - 销毁完成
  activated() {}, //如果页面有keep-alive缓存功能,这个函数会触发
};
</script>
<style scoped>
</style>

刷新显示出来了
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值