第2章-网关&商品后台管理&跨域.md 29 KB

第2章-后台管理&网关&跨域

学习目标

  • 掌握全局异常处理
  • 搭建微服务网关配置动态路由
  • 搭建后台管理前端
  • 掌握CORS跨域解决方案
  • 开发平台属性功能
  • 掌握Nacos配置文件统一管理

1. 全局异常处理

在项目中出现异常是在所难免的,但是出现异常后怎么处理?

默认我们需要service层的异常需要抛出,而servcie层被Spring管理,默认Spring的事务回滚只对RunTimeException起作用,所以我们要把service层的编译器异常转换为运行时异常抛出。

只有这种异常不需要影响业务,或者通过这种异常可以执行其他业务,我们才需要try

1.1 场景预设

1.1.1 场景

我们预设这样一个场景,假如我们做新增商品,需要接收下面的参数:

price:价格 name:名称

1.1.2 代码

gmall-model中编写实体类,该实体类无实际业务仅为测试使用:

@Data
public class Item {
    private Integer id;
    private String name;
    private Long price;
}

controller:

package com.atguigu.gmall.product.controller;

import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.product.model.Item;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("admin")
public class ItemController {


    @PostMapping("item")
    public Result<Item> saveItem(Item item) {
        // 模拟业务执行出现异常
        int i = 1/0;
        // 保存业务
        System.out.println("保存成功");
        return Result.build(item, ResultCodeEnum.SUCCESS);
    }
}

1.2 统一异常处理

项目开发中肯定会设置全局异常处理,不管系统发生了任何不可知的异常信息,都应该给用户返回友好提示信息。

service-util模块中新建类:GlobalExceptionHandler

package com.atguigu.gmall.common.config;

import com.atguigu.gmall.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理:
 * 对controller层产生代理对象-生成异常通知。发生异常都要在这里统一处理,相应Result
 *
 * @author: atguigu
 * @create: 2023-07-24 09:49
 */
@Slf4j
@RestControllerAdvice // 等于@ControllerAdvice+@ResponseBody
public class GlobalExceptionHandler {


    /**
     * 当异常内部发生运行时异常,走该方法执行逻辑返回给前端
     *
     * @param e
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    public Result runtimeException(RuntimeException e) {
        log.error("[全局异常处理],调用发生异常:{}", e);
        return Result.fail().message(e.getMessage());
    }


    /**
     * 当异常Exception异常,走该方法执行逻辑返回给前端
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public Result runtimeException(Exception e) {
        log.error("[全局异常处理],调用发生异常:{}", e);
        return Result.fail().message(e.getMessage());
    }
}

1.3 集成到项目中使用

在业务微服务模块中启动类所在包为:com.atguigu.gmall 会自动的扫描到service-util模块中全局异常处理类。

一定要保证启动类能够扫描service-util模块中全局异常处理类,否则会出现全局异常捕获失效。

2. 搭建网关服务

不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:

  • 客户端会多次请求不同的微服务,增加了客户端的复杂性
  • 存在跨域请求,在一定场景下处理相对复杂
  • 认证复杂,每个服务都需要独立认证
  • 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施
  • 某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难

以上这些问题可以借助网关解决。

网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 网关来做,这样既提高业务灵活性又不缺安全性,典型的架构图如图所示:

1585846768368

优点如下:

  • 安全 ,只有网关系统(Nginx,Gateway)对外进行暴露,微服务可以隐藏在内网,通过防火墙保护。
  • 易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
  • 易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
  • 减少了客户端与各个微服务之间的交互次数
  • 易于统一授权。

总结:微服务网关就是一个系统,通过暴露该微服务网关系统,方便我们进行相关的鉴权,安全控制,日志统一处理,易于监控的相关功能。

实现微服务网关的技术有很多,

  • Nginx: Nginx (engine x) 是一个高性能的HTTP反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务
  • Zuul: 是 Netflix 出品的一个基于 JVM 路由和服务端的负载均衡器。
  • Spring-cloud-gateway, : 是spring 出品的基于spring 的网关项目,集成断路器,路径重写,性能比Zuul好(Gateway组件底层WebFlux框架-响应式编程-异步非阻塞)。

我们使用gateway这个网关技术,无缝衔接到基于SpringCloud的微服务开发中来。

gateway官网:https://spring.io/projects/spring-cloud-gateway

2.1 搭建gmall-gateway

点击gmall-parent,选择New–>Module,操作如下

img

点击下一步

点击下一步

点击完成

2.2 配置pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>gmall-parent</artifactId>
        <groupId>com.atguigu.gmall</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>gmall-gateway</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.atguigu.gmall</groupId>
            <artifactId>common-util</artifactId>
            <version>1.0</version>
        </dependency>

        <!-- 服务注册 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 服务配置-->
        <!--
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            </dependency>
        -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

    </dependencies>
</project>

2.3 启动类

启动类:

package com.atguigu.gmall;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @author: atguigu
 * @create: 2022-12-23 10:50
 */
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApp {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApp.class, args);
    }
}

2.4 配置文件

在resources 目录下新建配置文件:application.yml

# 端口80 服务名称 nacos注册服务 动态路由
server:
  port: 80
spring:
  application:
    name: server-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.200.128:8848
    gateway:
      discovery:      #是否与服务发现组件进行结合,通过 serviceId(必须设置成大写) 转发到具体的服务实例。默认为false,设为true便开启通过服务中心的自动根据 serviceId 创建路由的功能。
        locator:      #路由访问方式:http://Gateway_HOST:Gateway_PORT/大写的serviceId/**,其中微服务应用名默认大写访问。
          enabled: true
      routes:
        # id:路由名称
        - id: service-product
          # uri:转发地址 lb:负载均衡协议 目标微服务名称 底层基于Ribbon实现负载均衡
          uri: lb://service-product
          # 断言
          predicates:
            # 匹配访问路径 地址栏中包含"product"都转发uri对应目标服务中
            - Path=/*/product/** # 路径匹配

3. 搭建后台管理前端

  1. 拷贝配套资料中的前端项目页面,放入一个没有中文目录的文件下

    image-20221128191338161

  2. 这是一个用nodejs构建的项目,解压后进入项目根目录,打开cmd窗口执行:

    • npm install [安装依赖 node_modules] 项目库中有node_modules 就不需要执行npm install(已有)

    • npm run dev

    • 直接访问浏览器
  3. 将两个配置文件 :第一个为网关地址,第二个为项目访问地址

在idea里引入工程,需要idea中配置

  • 安装vuejs插件

image-20221223112350161

  • 配置JavaScript版本为6

image-20221223112423154

  • 打开package.json文件 执行启动脚本

image-20221223112655851

注意:如果出现未找到node-sass模块,只需要在窗口中运行

npm install node-sass 即可,然后重新npm install node-sass,npm run dev 运行项目的时候,没有提示node-sass 模块未找到,需要看一下当前的nodejs 版本

node -v : 建议v10.14.3

可以通过8888端口即可访问:

进入首页后,点击左侧菜单"基本信息管理"->"平台属性列表"发现页面没有如期显示分类以及属性信息,打开浏览器调试工具查看console选项查看控制台报错信息如下:原因为跨域问题

image-20221128220514140

4. 跨域问题

跨域:浏览器对于javascript的同源策略的限制 。

以下情况都属于跨域:

跨域原因说明 示例
域名不同 www.jd.comwww.taobao.com
域名相同,端口不同 www.jd.com:8080www.jd.com:8081
二级域名不同 item.jd.commiaosha.jd.com

如果域名和端口都相同,但是请求路径不同,不属于跨域,如:

www.jd.com/item

www.jd.com/goods

http和https也属于跨域

而我们刚才是从manager.gmall.com去访问api.gmall.com,这属于域名不同,跨域了。

4.1 为什么有跨域问题?

跨域不一定都会有跨域问题

因为跨域问题浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能与当前页域名相同的路径,这能有效的阻止跨站攻击。

因此:跨域问题 是针对ajax的一种限制

但是这却给我们的开发带来了不便,而且在实际生产环境中,肯定会有很多台服务器之间交互,地址和端口都可能不同,怎么办?

4.2 解决跨域问题的方案

目前比较常用的跨域解决方案有3种:

  • Jsonp

最早的解决方案,利用script标签可以跨域的原理实现。

限制:

  • 需要服务的支持
  • 只能发起GET请求

  • nginx反向代理

思路是:利用nginx把跨域反向代理为不跨域,支持各种请求方式

缺点:需要在nginx进行额外配置,语义不清晰

  • CORS

规范化的跨域请求解决方案,安全可靠。

优势:

  • 在服务端进行控制是否允许跨域,可自定义规则
  • 支持各种请求方式

缺点:

  • 会产生额外的请求

我们这里会采用cors的跨域方案。

4.3 什么是cors

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

  • 浏览器端:

目前,所有浏览器都支持该功能(IE10以下不行)。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。

  • 服务端:

CORS通信与AJAX没有任何差别,因此你不需要改变以前的业务逻辑。只不过,浏览器会在请求中携带一些头信息,我们需要以此判断是否允许其跨域,然后在响应头中加入一些信息即可。这一般通过过滤器完成即可。

4.4 原理有点复杂

预检请求

跨域请求会在正式通信之前,增加一次HTTP查询请求(POST),称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

一个“预检”请求的样板:

OPTIONS /cors HTTP/1.1
Origin: http://localhost:1000
Access-Control-Request-Method: GET
Access-Control-Request-Headers: X-Custom-Header
User-Agent: Mozilla/4.0...
  • Origin:会指出当前请求属于哪个域(协议+域名+端口)。服务会根据这个值决定是否允许其跨域。

  • Access-Control-Request-Method:接下来会用到的请求方式,比如PUT

  • Access-Control-Request-Headers:会额外用到的头信息

预检请求的响应

服务的收到预检请求,如果许可跨域,会发出响应:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://miaosha.jd.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 1728000
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

如果服务器允许跨域,需要在返回的响应头中携带下面信息:

  • Access-Control-Allow-Origin:可接受的域,是一个具体域名或者*(代表任意域名)
  • Access-Control-Allow-Credentials:是否允许携带cookie,默认情况下,cors不会携带cookie,除非这个值是true
  • Access-Control-Allow-Methods:允许访问的方式
  • Access-Control-Allow-Headers:允许携带的头
  • Access-Control-Max-Age:本次许可的有效时长,单位是秒,过期之前的ajax请求就无需再次进行预检了

有关cookie:

要想操作cookie,需要满足3个条件:

  • 服务的响应头中需要携带Access-Control-Allow-Credentials并且为true。
  • 浏览器发起ajax需要指定withCredentials 为true
  • 响应头中的Access-Control-Allow-Origin一定不能为*,必须是指定的域名

4.5 实现非常简单

CORS实现方式:

  • 每个微服务控制层类上加注解 @CrossOrigin 加在Web层Controller类上 不建议使用,维护麻烦
  • 网关中解决
    • 配置类:编写过滤器配置跨域规则(采用)
    • 配置文件:配置跨域规则

虽然原理比较复杂,但是前面说过:

  • 浏览器端都有浏览器自动完成,我们无需操心
  • 服务端可以通过拦截器统一实现,不必每次都去进行跨域判定的编写。

事实上,SpringCloudGateway中只需要注册过滤器对象,内部已经实现了刚才所讲的判定逻辑。我们只需编写跨域规则即可:

package com.atguigu.gmall.gateway.filter;

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;

/**
 * @author: atguigu
 * @create: 2023-07-24 11:41
 */
@Configuration
public class CorsFilterConfig {


    /**
     * 配置CORS过滤配置:配置跨域规则
     *
     * @return
     */
    @Bean
    public CorsWebFilter corsWebFilter() {
        // 1.创建跨域规则
        CorsConfiguration configuration = new CorsConfiguration();
        //1.1 指定允许哪些域名跨域访问
        configuration.addAllowedOrigin("*");

        //1.2 指定运行哪些额外请求头来进行访问(要求携带哪些特殊请求头才能跨域访问)
        configuration.addAllowedHeader("*");

        //1.3 指定运行哪些http方式访问
        configuration.addAllowedMethod("*");

        //1.4 指定是否携带Cookie
        configuration.setAllowCredentials(true);

        //1.5 设置预检请求有效期
        configuration.setMaxAge(3600L);

        //2.创建CORS配置对象
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        //
        source.registerCorsConfiguration("/**", configuration);
        //3. 创建跨域过滤器对象
        return new CorsWebFilter(source);
    }
}

4.6 测试

在后台管理页面中测试:

image-20221128233749227

5. 平台属性管理

5.1 代码生成器应用

  1. 从配套资料11 逆向工程中的mybatis-plus-code模块导入到idea中

    image-20221212151855192

  2. 修改CodeGenerator中生成方法

image-20221212152056774

  1. 执行后生成的代码会到目标微服务src目录下,控制台中输入要生成基础代码表名称,多个表之间采用逗号隔开

image-20221212152218538

5.2 数据模型

数据库中的表!

img

5.3 属性新增/修改

YAPI接口地址:http://192.168.200.128:3000/project/11/interface/api/211

5.3.1 控制层

新建BaseAttrInfoController中增加方法处理保存属性方法

/**
 * 保存或者修改平台属性以及值
 *
 * @param baseAttrInfo
 * @return
 */
@PostMapping("/saveAttrInfo")
public Result saveOrUpdateAttrInfo(@RequestBody BaseAttrInfo baseAttrInfo) {
    //1.大多数增删改业务接口一般不需响应业务数据,只要没发生异常就认为执行成功
    baseAttrInfoService.saveOrUpdateAttrInfo(baseAttrInfo);
    //2.有全局异常处理投递,业务层捕获会进行事务回滚
    return Result.ok();
}

5.3.2. 业务层

  1. 业务层接口BaseAttrInfoService中新增方法

    /**
    * 保存或者修改平台属性以及值
    *
    * @param baseAttrInfo
    * @return
    */
    void saveOrUpdateAttrInfo(BaseAttrInfo baseAttrInfo);
    
  2. 业务层实现类BaseAttrInfoServiceImpl实现方法

    @Autowired
    private BaseAttrValueService baseAttrValueService;
       
       
    /**
    * 保存或者修改平台属性以及值
    *
    * @param baseAttrInfo
    * @return
    */
    @Override
    @Transactional(rollbackFor = Exception.class) //默认捕获到RuntimeException才会回滚
    public void saveOrUpdateAttrInfo(BaseAttrInfo baseAttrInfo) {
       //1.通过提交ID判断是新增操作还是修改操作
       if (baseAttrInfo.getId() == null) {
           //2.新增
           //2.1 新增平台属性记录 保存后平台属性对象中有id
           this.save(baseAttrInfo); //主键回查 采用:selectKey标签
           //2.2 新增平台属性值
           this.saveBatchAttrValue(baseAttrInfo.getId(), baseAttrInfo.getAttrValueList());
       } else {
           //3.修改
           //3.1 平台属性信息修改
           this.updateById(baseAttrInfo);
           //3.2 平台属性值 考虑:有新增属性值  删除属性值  做法:先将旧的平台属性值删除(逻辑,物理) 再新增
           //3.2.1 先根据平台属性ID删除属性值
           LambdaQueryWrapper<BaseAttrValue> queryWrapper = new LambdaQueryWrapper<>();
           queryWrapper.eq(BaseAttrValue::getAttrId, baseAttrInfo.getId());
           baseAttrValueService.remove(queryWrapper);
           //3.2.2 再新增属性值列表
           this.saveBatchAttrValue(baseAttrInfo.getId(), baseAttrInfo.getAttrValueList());
       }
    }
       
       
    /**
    * 批量新增平台属性值
    * @param arttrId
    * @param attrValueList
    */
    public void saveBatchAttrValue(Long arttrId, List<BaseAttrValue> attrValueList) {
       if (!CollectionUtils.isEmpty(attrValueList)) {
           attrValueList.stream().forEach(baseAttrValue -> {
               //2.2.1 为平台属性值关联平台属性ID
               baseAttrValue.setAttrId(arttrId);
           });
           //2.2.2 批量保存平台属性值  insert into tab values(1,'a'),(2,'b')
           baseAttrValueService.saveBatch(attrValueList);
       }
    }
    

注意:实现类方法添加:@Transactional

5.4 属性值回显

YAPI接口地址:

5.4.1. 控制层

接口选中修改数据 , 根据该attrId 去查找AttrInfo下包含 List !

所以在返回的时候,需要返回List

BaseAttrInfoController中增加方法处理*查询平台属性集合方法

/**
 * 根据平台属性ID查询属性值集合
 * @param attrId
 * @return
 */
@GetMapping("/getAttrValueList/{attrId}")
public Result getAttrValueList(@PathVariable("attrId") Long attrId){
    List<BaseAttrValue> list = baseAttrInfoService.getAttrValueList(attrId);
    return Result.ok(list);
}

5.4.2. 业务层

  1. 业务层接口BaseAttrInfoService中新增方法

    /**
    * 根据平台属性ID查询属性值集合
    * @param attrId
    * @return
    */
    List<BaseAttrValue> getAttrValueList(Long attrId);
    
  2. 业务层实现类BaseAttrInfoServiceImpl实现方法

    /**
    * 根据平台属性ID查询该属性包含属性值列表
    * @param attrId
    * @return
    */
    @Override
    public List<BaseAttrValue> getAttrValueList(Long attrId) {
       LambdaQueryWrapper<BaseAttrValue> queryWrapper = new LambdaQueryWrapper<>();
       queryWrapper.eq(BaseAttrValue::getAttrId, attrId);
       return baseAttrValueService.list(queryWrapper);
    }
    

6. 配置文件迁移nacos

6.1 安装 nacos

  1. 资源库获取nacos数据库表结构并且导入数据库

image-20230221155616478

  1. 通过容器管理工具http://192.168.200.128:19000/删除掉以前的Nacos
  2. 更改nacos启动配置参数

    docker run -d  \
    -e MODE=standalone  \
    -e PREFER_HOST_MODE=hostname  \
    -e SPRING_DATASOURCE_PLATFORM=mysql  \
    -e MYSQL_SERVICE_HOST=192.168.200.128 \
    -e MYSQL_SERVICE_PORT=3306  \
    -e MYSQL_SERVICE_USER=root  \
    -e MYSQL_SERVICE_PASSWORD=123456  \
    -e MYSQL_SERVICE_DB_NAME=nacos_config  \
    -p 8848:8848 \
    --name nacos \
    --restart=always \
    nacos/nacos-server:2.0.2
    

6.2 项目中集成

6.2.1. 导入依赖

gmall-gateway,还有gmall-service 父模块添加依赖

<!-- 配置-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

说明:搭建环境是我们注释了的,现在打开

6.2.2 改造service-product

  1. 删除之前的配置文件application.yml

  2. 添加配置文件:bootstrap.properties

    spring.application.name=service-product
    spring.profiles.active=dev
    spring.cloud.nacos.discovery.server-addr=192.168.200.128:8848
    spring.cloud.nacos.config.server-addr=192.168.200.128:8848
    spring.cloud.nacos.config.prefix=${spring.application.name}
    spring.cloud.nacos.config.file-extension=yaml
    spring.cloud.nacos.config.shared-configs[0].data-id=common.yaml
    

说明:

  • 配置文件统一配置到nacos配置中心

  • common.yaml为公共配置,后续有需要的service模块都可直接引用,避免重复配置

  1. Nacos配置列表中新增配置common.yaml配置文件如下(已完成):

    mybatis-plus:
     configuration:
       log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
     mapper-locations: classpath:mapper/*Mapper.xml
    feign:
     sentinel:
       enabled: true
     client:
       config:
         default:
           readTimeout: 3000
           connectTimeout: 1000
    spring:
     # zipkin:
     #   base-url: http://192.168.200.128:9411
     #   discovery-client-enabled: false
     #   sender:
     #     type: web
     cloud:
       sentinel:
         transport:
           dashboard: http://192.168.200.128:8080
     rabbitmq:
       host: 192.168.200.128
       port: 5672
       username: admin
       password: admin
       publisher-confirm-type: correlated
       publisher-returns: true
       listener:
         simple:
           acknowledge-mode: manual #默认情况下消息消费者是自动确认消息的,如果要手动确认消息则需要修改确认模式为manual
           prefetch: 1 # 消费者每次从队列获取的消息数量。此属性当不设置时为:轮询分发,设置为1为:公平分发
     redis:
       host: 192.168.200.128
       port: 6379
       database: 0
       timeout: 1800000
       lettuce:
         pool:
           max-active: 20 #最大连接数
           max-wait: -1    #最大阻塞等待时间(负数表示没限制)
           max-idle: 5    #最大空闲
           min-idle: 0     #最小空闲
     jackson:
       date-format: yyyy-MM-dd HH:mm:ss
       time-zone: GMT+8
    
  2. Nacos配置列表中新增商品模块配置文件service-product-dev.yaml

    server:
     port: 8206
    spring:
     datasource:
       type: com.zaxxer.hikari.HikariDataSource
       driver-class-name: com.mysql.jdbc.Driver
       url: jdbc:mysql://192.168.200.128:3306/gmall_product?characterEncoding=utf-8&useSSL=false
       username: root
       password: 123456
       hikari:
         connection-test-query: SELECT 1 # 自动检测连接
         connection-timeout: 60000 #数据库连接超时时间,默认30秒
         idle-timeout: 500000 #空闲连接存活最大时间,默认600000(10分钟)
         max-lifetime: 540000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
         maximum-pool-size: 12 #连接池最大连接数,默认是10
         minimum-idle: 10 #最小空闲连接数量
         pool-name: SPHHikariPool # 连接池名称
    

说明:其实配置属性还是以前项目的配置属性,只是变化了文件命名规则,配置项不变。

6.2.3 改造server-gateway

  1. 删除之前的配置文件application.yml

  2. 添加配置文件bootstrap.properties

    spring.application.name=server-gateway
    spring.profiles.active=dev
    spring.cloud.nacos.discovery.server-addr=192.168.200.128:8848
    spring.cloud.nacos.config.server-addr=192.168.200.128:8848
    spring.cloud.nacos.config.prefix=${spring.application.name}
    spring.cloud.nacos.config.file-extension=yaml
    
  3. Nacos配置列表中新增配置 server-gateway-dev.yaml配置文件如下(已完成):

    server:
     port: 80
    spring:
     application:
       name: server-gateway
     cloud:
       nacos:
         discovery:
           server-addr: 192.168.200.128:8848
           ip: 127.0.0.1
       gateway:
         discovery:      #是否与服务发现组件进行结合,通过 serviceId(必须设置成大写) 转发到具体的服务实例。默认为false,设为true便开启通过服务中心的自动根据 serviceId 创建路由的功能。
           locator:      #路由访问方式:http://Gateway_HOST:Gateway_PORT/大写的serviceId/**,其中微服务应用名默认大写访问。
             enabled: true
         routes:
           - id: service-product
             uri: lb://service-product
             predicates:
               - Path=/*/product/** # 路径匹配
    

说明:其他服务配置文件统一已经在Nacos提供。或者配套资料中也有配置文件压缩包Nacos中直接导入即可,注意业务微服务配置文件中数据库连接信息需要修改:IP地址,数据库密码.