• 商城项目07_网关工程初步搭建、商品分类树状结构展示、网关配置、解决跨域问题


    ①. 网关工程初步搭建

    • ①. 搭建的工程如图所示,并在gateway服务中开启注册服务发现@EnableDiscoveryClient
      在这里插入图片描述
    @EnableDiscoveryClient
    //由于我们在common工程里面引入了数据库的依赖,网关工程中没有进行配置,这里将其忽略,否则会报错误信息
    @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
    public class GulimallGatewayApplication {
        public static void main(String[] args) {
            SpringApplication.run(GulimallGatewayApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • ②. 在nacos配置中心中配置如下文件
      在这里插入图片描述在这里插入图片描述

    • ③. bootstrap.yml

    spring:
      cloud:
        nacos:
          config:
            server-addr: 127.0.0.1:8848
            namespace: 3fa6c8bc-2d25-4824-9773-ca6e14a42308
            file-extension: yaml
      application:
        name: gulimall-gateway
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • ④. application.yaml
    spring:
      cloud:
        gateway:
          routes:
            - id: test_route1
              uri: http://localhost:7000
              predicates:
                - Path=/coupon/coupon/test/**
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • ⑤. 测试:当我们访问 http://localhost:88/coupon/coupon/test 会在网关进行路径匹配后进行跳转到coupon优惠卷服务的controller
      在这里插入图片描述

    ②. 拼装获取树形菜单结构

    • ①. 数据库表设置
      在这里插入图片描述
    CREATE TABLE `pms_category` (
      `cat_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '分类id',
      `name` char(50) DEFAULT NULL COMMENT '分类名称',
      `parent_cid` bigint(20) DEFAULT NULL COMMENT '父分类id',
      `cat_level` int(11) DEFAULT NULL COMMENT '层级',
      `show_status` tinyint(4) DEFAULT NULL COMMENT '是否显示[0-不显示,1显示]',
      `sort` int(11) DEFAULT NULL COMMENT '排序',
      `icon` char(255) DEFAULT NULL COMMENT '图标地址',
      `product_unit` char(50) DEFAULT NULL COMMENT '计量单位',
      `product_count` int(11) DEFAULT NULL COMMENT '商品数量',
      PRIMARY KEY (`cat_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1433 DEFAULT CHARSET=utf8mb4 COMMENT='商品三级分类';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • ②. 导入数据(将sql脚本导入进来)

    • ③. 使用java8新特性查找三级联洞并封装成树形结构

    @RestController
    @RequestMapping("product/category")
    public class CategoryController {
        @Autowired
        private CategoryService categoryService;
        /**
         * 查出所有分类、以及子分类,以树形结构组装起来
         */
        @RequestMapping("/list/tree")
        //@RequiresPermissions("product:category:list")
        public R list(){
            List<CategoryEntity> entities = categoryService.listWithTree();
            return R.ok().put("data", entities);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
        @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;
        }
    
        //递归查找所有菜单的子菜单
        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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    @Data
    @TableName("pms_category")
    public class CategoryEntity implements Serializable {
    	private static final long serialVersionUID = 1L;
    	/**
    	 * 分类id
    	 */
    	@TableId
    	private Long catId;
    	/**
    	 * 分类名称
    	 */
    	private String name;
    	/**
    	 * 父分类id
    	 */
    	private Long parentCid;
    	/**
    	 * 层级
    	 */
    	private Integer catLevel;
    	/**
    	 * 是否显示[0-不显示,1显示]
    	 */
    	@TableLogic(value = "1",delval = "0")
    	private Integer showStatus;
    	/**
    	 * 排序
    	 */
    	private Integer sort;
    	/**
    	 * 图标地址
    	 */
    	private String icon;
    	/**
    	 * 计量单位
    	 */
    	private String productUnit;
    	/**
    	 * 商品数量
    	 */
    	private Integer productCount;
    	@TableField(exist = false)
    	private List<CategoryEntity>children;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • ④. 结果测试 http://localhost:10001/product/category/list/tree
      在这里插入图片描述

    ③. 将renren-fast、product项目与nacaos结合

    • ①. 在renren-fast导入公共依赖,并在主启动类上加上@EnableDiscoveryClient
    @EnableDiscoveryClient
    @SpringBootApplication
    public class RenrenApplication {
    	public static void main(String[] args) {
    		SpringApplication.run(RenrenApplication.class, args);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • ②. 在配置文件中将reren-fast注入到注册中心nacos、由于在common工程中导入了nacos的配置文件,这里也将config进行配置
    spring:
      application:
        name: renren-fast
      cloud:
        nacos:
          discovery:
            server-addr: 127.0.0.1:8848
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    # bootstrap.properties
    spring.application.name=renren-fast
    spring.cloud.nacos.config.server-addr=127.0.0.1:8848
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    ④. 前端页面如何新增商品系统分类维护

    • ①. 启动renren-fast和renren-fast-vue,登录系统后新增分类维护菜单栏
      在这里插入图片描述
      在这里插入图片描述在这里插入图片描述

    • ②. 通过角色管理role,看到url的路径是sys/role,在浏览器上将/变成了-(sys/role),打开vscode可以看到关系如下:在这里插入图片描述

    • ③. 在vscode中新建product文件夹,新建category.vue

    <template>
      <div class="">
        <el-tree
          :data="data"
          :props="defaultProps"
          @node-click="handleNodeClick"
        >el-tree>
      div>
    template>
    
    <script>
    //这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
    //例如:import 《组件名称》 from '《组件路径》';
    
    export default {
      //import引入的组件需要注入到对象中才能使用
      components: {},
      data() {
        //这里存放数据
        return {};
      },
      //监听属性 类似于data概念
      computed: {},
      data() {
        return {
          data: [],
          defaultProps: {
            children: "children",
            label: "label"
          }
        };
      },
      methods: {
        handleNodeClick(data) {
          console.log(data);
        },
        getMenus() {
          this.$http({
            url: this.$http.adornUrl("/product/category/list/tree"),
            method: "get"
          }).then(({ data }) => {
            if (data && data.code === 0) {
              this.data = data.data;
            } else {
              this.dataList = [];
            }
          });
        }
      },
      //生命周期 - 创建完成(可以访问当前this实例)
      created() {
        this.getMenus();
      },
      //生命周期 - 挂载完成(可以访问DOM元素)
      mounted() {}
    };
    script>
    <style scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • ④. 规定以后前端发送来的请求都经过网关,并且带上api路径

    在这里插入图片描述

    • ⑤. 配置gateway网关设置,admin_route
      如果我们在http://localhost:8001/#/login 这样的方式进行登录会出现跨域问题
    spring:
      cloud:
        gateway:
          routes:
            - id: test_route1
              uri: http://localhost:7000
              predicates:
                - Path=/coupon/coupon/test/**
            - id: admin_route
              uri: lb://renren-fast
              predicates:
                - Path=/api/**
              filters:
                - RewritePath=/api/(?>/?.*), /renren-fast/$\{segment}
    # 前端项目 /api
    # http://localhost:88/api/captcha.jpg?uuid=72b9da67-0130-4d1d-8dda-6bfe4b5f7935
    # http://renren-fast:8080/renren-fast/captcha.jpg
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    ⑤. 解决跨域问题 掌握

    • ①. 登录,还是报错:(出现了跨域的问题,就是说vue项目是8001端口,却要跳转到88端口,为了安全性,不可以)
      8001/#/login:1 Access to XMLHttpRequest at ‘http://localhost:88/api/sys/login’ 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.
      从8001访问88,引发CORS跨域请求,浏览器会拒绝跨域请求。具体来说当前页面是8001端口,但是要跳转88端口,这是不可以的(post请求json可以)

    在这里插入图片描述

    跨域请求流程:
    非简单请求(PUT、DELETE),需要先发送预检请求
    
    
           -----1、预检请求、OPTIONS ------>
           <----2、服务器响应允许跨域 ------
    浏览器 |                               |  服务器
           -----3、正式发送真实请求 -------->
           <----4、响应数据   --------------
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    • ⑤. 跨域的解决方案
    1. 设置nginx包含admin和gateway。都先请求nginx,这样端口就统一了
    2. 让服务器告诉预检请求能跨域(我们的项目使用第二种方式解决问题)

    在这里插入图片描述

    • ⑥. 我们在网关的配置如下内容进行解决跨域问题(添加响应头)
    1. Access-Control-Allow-Origin:支持哪些来源的请求跨域
    2. Access-Control-Allow-Methods:支持哪些方法跨域
    3. Access-Control-Allow-Credentials:跨域请求默认不包含cookie,设置为true可以包含 cookie
    4. Access-Control-Expose-Headers:跨域请求暴露的字段(CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段: Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定)
    5. Access-Control-Max-Age:表明该响应的有效时间为多少秒。在有效时间内,浏览器无须为同一请求再次发起预检请求。请注意,浏览器自身维护了一个最大有效时间,如果 该首部字段的值超过了最大有效时间,将不会生效
    package com.atguigu.gulimall.gateway.config;
    @Configuration // gateway
    public class GulimallCorsConfiguration {
        @Bean // 添加过滤器
        public CorsWebFilter corsWebFilter(){
            // 基于url跨域,选择reactive包下的
            UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
            // 跨域配置信息
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            // 允许跨域的头
            corsConfiguration.addAllowedHeader("*");
            // 允许跨域的请求方式
            corsConfiguration.addAllowedMethod("*");
            // 允许跨域的请求来源
            corsConfiguration.addAllowedOrigin("*");
            // 是否允许携带cookie跨域
            corsConfiguration.setAllowCredentials(true);
    
            // 任意url都要进行跨域配置
            source.registerCorsConfiguration("/**",corsConfiguration);
            return new CorsWebFilter(source);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • ⑦. 再次访问:http://localhost:8001/#/login
      同源策略禁止读取:http://localhost:88/api/sys/login的远程资源(原因:不允许多个CORS头),在renren-fast也配置了跨域,需要将renren-fast中的跨域也注释掉
      在这里插入图片描述在这里插入图片描述

    ⑥. 配置product网关、前端展示

    • ①. 这个时候去访问在页面访问:http://localhost:88/api/product/category/list/tree可以显示数据
      (在product的配置文件中配置注册中心和配置中心的配置文件)
    #  如下的配置在nacos中也进行了配置(从spring 到 port: 88),可以进行注释掉
    #  当一个请求过来的时候,会交给网关进行处理,通过一系列的预言,如果预言为真,会转到指定的服务,转到指定服务的时候,会经过一系列的过滤器
    spring:
    #  application:
    #    name: gulimall-gateway
    #  cloud:
    #    nacos:
    #      discovery:
    #        server-addr: 127.0.0.1:8848
    #server:
    #  port: 88
      cloud:
        gateway:
          routes:
            # 测试网关的功能
            - id: test_route1
              uri: http://localhost:7001
              predicates:
                - Path=/coupon/coupon/nacos/config/simple/**
            # 商品服务网关配置(注意需要把product_route放在admin_route前面)
            # http://localhost:88/api/product/category/list/tree
            # http://localhost:10000/product/category/list/tree
            - id: product_route
              uri: lb://gulimall-product
              predicates:
                - Path=/api/product/**
              filters:
                - RewritePath=/api/(?>/?.*), /$\{segment}
            - id: admin_route
              uri: lb://renren-fast
              predicates:
                - Path=/api/**
              filters:
                - RewritePath=/api/(?>/?.*), /renren-fast/$\{segment}
    # 前端项目 /api
    # http://localhost:88/api/captcha.jpg?uuid=72b9da67-0130-4d1d-8dda-6bfe4b5f7935
    # http://renren-fast:8080/renren-fast/captcha.jpg
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

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

    在这里插入图片描述

    • ②. 设置前端代码,在页面展示树状结构查询
    
    <template>
      <div class="">
        <el-tree
          :data="menus"
          :props="defaultProps"
          @node-click="handleNodeClick"
        >el-tree>
      div>
    template>
    
    <script>
    //这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
    //例如:import 《组件名称》 from '《组件路径》';
    
    export default {
      //import引入的组件需要注入到对象中才能使用
      components: {},
      data() {
        //这里存放数据
        return {};
      },
      //监听属性 类似于data概念
      computed: {},
      data() {
        return {
          menus: [],
          defaultProps: {
            children: "children",
            label: "name"
          }
        };
      },
      methods: {
        handleNodeClick(data) {
          console.log(data);
        },
        getMenus() {
          this.$http({
            url: this.$http.adornUrl("/product/category/list/tree"),
            method: "get"
          }).then(({ data }) => {
            if (data && data.code === 0) {
              this.menus = data.data;
            }
          });
        }
      },
      //生命周期 - 创建完成(可以访问当前this实例)
      created() {
        this.getMenus();
      },
      //生命周期 - 挂载完成(可以访问DOM元素)
      mounted() {}
    };
    script>
    <style scoped>style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    在这里插入图片描述

  • 相关阅读:
    JAVA计算机毕业设计资源循环利用Mybatis+源码+数据库+lw文档+系统+调试部署
    GDB 跳转执行
    基于STM32六路DS18B20温度监测报警仿真设计( proteus仿真+程序)
    Web前端、后端与建站:全方位解析四大基石、五大挑战、六大技术与七大策略
    基于全景相机的视觉SLAM
    性能优化:TCP连接优化之四次挥手
    计算机毕业设计ssm社会救援力量信息管理统计系统6q3cn系统+程序+源码+lw+远程部署
    【CV】第 10 章:使用 R-CNN、SSD 和 R-FCN 进行目标检测
    企业怎么通过数字化工具来实现数字化转型?
    mac 安装docker
  • 原文地址:https://blog.csdn.net/TZ845195485/article/details/126754515