[Spring Cloud] 简单搭建与请求转发

文章目录

  • 简介
  • 相关链接
  • 搭建
    • 选择Spring Boot版本
    • 选择组件版本
    • 创建nacos配置
      • 创建网关gateway配置文件
      • image.png创建微服务Spring Boot配置文件
  • gateway项目配置
    • gateway项目文件
      • pom.xml
      • Application.java
      • bootstrap.yml
      • logback-spring.xml
    • 启动gateway
  • 微服务配置
    • 微服务项目文件
      • pom.xml
      • Application.java
      • DemoController.java
      • bootstrap.yml
      • logback-spring.xml
    • 启动微服务
  • 最终
    • 检查服务是否注册
    • 测试转发
    • 常见错误
    • Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better!

简介

注意:
本文面向新手,以快速集成与实现微服务的请求转发两个目的。有关于相关拦截器等实现,可参考后续发布的文章。如有其他需求可参考其他博主,或者等待更新。

本文gateway与微服务已开源到gitee
杉极简/gateway网关阶段学习

Spring Cloud Gateway是Spring Cloud生态系统中的一个组件,用于构建基于路由的网关服务。它可以用作传统的反向代理,同时提供了一些额外的功能,如路由、过滤、负载均衡、限流、安全性等。
Spring Cloud Gateway的主要作用:

  1. 路由转发:根据请求的URI和其他条件,将请求转发到后端的微服务实例。可以配置多个路由规则,每个规则可以指定不同的目标服务。
  2. 过滤器:允许对请求和响应进行处理,并在路由之前或之后应用一些额外的逻辑。可以编写自定义的过滤器来实现日志记录、身份验证、请求修改等功能。
  3. 负载均衡:支持在路由请求时进行负载均衡,自动选择后端的多个实例之一来处理请求。可以集成Spring Cloud Ribbon或其他负载均衡器来实现。
  4. 限流:可以配置限流策略,防止流量过大导致服务不稳定。通过限制每秒钟处理的请求数量或者并发请求数量来控制流量。
  5. 安全性:提供安全功能,如跨站请求伪造(CSRF)保护、跨源资源共享(CORS)支持等。
  6. 监控和指标:集成了Spring Boot Actuator,可以通过HTTP端点查看网关的健康状况、指标信息等。

总的来说,Spring Cloud Gateway可以作为微服务架构中的入口,对外提供统一的API接口和服务访问入口,同时可以通过配置灵活地实现路由、过滤、负载均衡等功能,以满足不同场景下的需求。

相关链接

Spring Cloud 官方
https://spring.io/projects/spring-cloud

Spring Cloud Alibaba
https://sca.aliyun.com/zh-cn/

搭建

选择Spring Boot版本

目前多数企业(截至文章创作之日 2023-3-24)仍然在使用JDK8、Spring Boot 2.x.x、Spring Boot 1.x.x。
本文并不采用最新的JDK17、Spring Boot 3.x.x。
我们仍探究属于JDK8中,最后一个Could版本Spring Cloud Alibaba Version 2021.0.5.0
更多的版本对应关系可查看官网:Spring Cloud Alibaba 版本说明

Spring Cloud Alibaba VersionSpring Cloud VersionSpring Boot Version
2021.0.5.0Spring Cloud 2021.0.52.6.13

选择组件版本

为了首先实现转发服务,我们优先集成Nacos 2.2.0

Spring Cloud Alibaba VersionSentinel VersionNacos VersionRocketMQ VersionDubbo VersionSeata Version
2021.0.5.01.8.62.2.04.9.4~1.6.1

创建nacos配置

没有安装nacos的见这篇文章[服务器] 安装Nacos2.2.0-Windows-CSDN博客

创建网关gateway配置文件

spring:
  cloud:
    gateway:
      httpclient:
        pool:
          # 根据需要调整
          maxIdleTime: 10000
      routes:
        # 路由的ID,没有固定规则但要求唯一,建议配合服务名
        - id: fir-node-two-dev
          # 转发之前去掉第1层路径(此次访问下级路由时由原/get/value变成了/tick/get/value)
          filters:
            - StripPrefix=1
          predicates:
            - name: Path
              # 断言,路径相匹配的进行路由
              args[pattern]: /tick/**
            # 匹配连接nacos的服务作为后端服务的路由地址
          uri: lb://fir-node-two-dev

        # 转发websocket
        - id: fir-node-two-dev
          # 转发之前去掉第1层路径(此次访问下级路由时由原/ws变成了/socket/ws)
          filters:
            - StripPrefix=1
          uri: lb:ws://fir-node-two-dev
          predicates:
            - name: Path
              # 断言,路径相匹配的进行路由
              args[pattern]: /socket/**

image.png创建微服务Spring Boot配置文件

创建一个配置文件名为:fir-node-two-dev.yml

aa: 测试微服务1

image.png
再创建一个Spring Boot 2.6.13的微服务。
连接到fir-node-two-dev.yml配置文件。并使用fir-node-two-dev配置服务

gateway项目配置

gateway目前需要做的是,注册到Nacos,并使用一个Nacos配置,配置相关的转发服务配置。

gateway项目文件

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.13</version>
        <relativePath/>
    </parent>
    <groupId>com.fir</groupId>
    <artifactId>geteway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>fir_java_gateway</name>
    <description>fir_java_gateway</description>
    <properties>
        <java.version>1.8</java.version>
        <spring.cloud.version>2021.0.5</spring.cloud.version>
        <alibaba.cloud.version>2021.0.5.0</alibaba.cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--        cloud gateway 网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <!--客户端负载均衡loadbalancer-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <!--feign组件-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.github.ben-manes.caffeine/caffeine -->
        <!--        避免
                    LoadBalancerCacheManager not available, returning delegate without caching
                    的错误
                    -->
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>2.8.8</version>
        </dependency>
        <!--        网关熔断机制,Hystrix,实现熔断功能-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.2.10.RELEASE</version>
        </dependency>


        <!-- nacos客户端依赖 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--服务配置依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.83</version>
        </dependency>

        <!--        配置注解执行器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${alibaba.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Application.java

package com.fir.gateway;

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


/**
 * @author dpe
 * @create 2022/8/4 22:58
 */
@EnableDiscoveryClient
@SpringBootApplication
public class Application {


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

}

bootstrap.yml

server:
  port: 51001
spring:
  application:
    name: fir-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:18884
        username: nacos
        password: nacos
        service: fir-gateway
      config:
        server-addr: localhost:18884
        file-extension: yml
        username: nacos
        password: nacos
        group: DEFAULT_GROUP

# 引入logger日志相关配置
logging:
  config: classpath:logback-spring.xml

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="10 seconds">

  <!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->

  <contextName>logback</contextName>
  <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
  <property name="log.path" value="logs" />

  <!-- 彩色日志 -->
  <!-- 彩色日志依赖的渲染类 -->
  <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
  <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
  <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
  <!-- 彩色日志格式 -->
  <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>


  <!--输出到控制台-->
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>info</level>
    </filter>
    <encoder>
      <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
      <!-- 设置字符集 -->
      <charset>UTF-8</charset>
    </encoder>
  </appender>


  <!--输出到文件-->

  <!-- 时间滚动输出 level为 DEBUG 日志 -->
  <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 正在记录的日志文件的路径及文件名 -->
    <file>${log.path}/log_debug.log</file>
    <!--日志文件输出格式-->
    <encoder>
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      <charset>UTF-8</charset> <!-- 设置字符集 -->
    </encoder>
    <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- 日志归档 -->
      <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>100MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
      <!--日志文件保留天数-->
      <maxHistory>15</maxHistory>
    </rollingPolicy>
    <!-- 此日志文件只记录debug级别的 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>debug</level>
      <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 WARN 日志 -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_warn.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
        以及指定<appender>。<logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
              如果未设置此属性,那么当前logger将会继承上级的级别。
        addtivity:是否向上级logger传递打印信息。默认是true。
    -->
    <!--<logger name="org.springframework.web" level="info"/>-->
    <!--<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>-->
    <!--
        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
        第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
        第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
     -->


    <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        不能设置为INHERITED或者同义词NULL。默认是DEBUG
        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
    -->

    <!--开发环境:打印控制台-->
    <springProfile name="dev">
        <logger name="com.nmys.view" level="debug"/>
    </springProfile>

    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="DEBUG_FILE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="WARN_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>

    <!--生产环境:输出到文件-->
    <!--<springProfile name="pro">-->
    <!--<root level="info">-->
    <!--<appender-ref ref="CONSOLE" />-->
    <!--<appender-ref ref="DEBUG_FILE" />-->
    <!--<appender-ref ref="INFO_FILE" />-->
    <!--<appender-ref ref="ERROR_FILE" />-->
    <!--<appender-ref ref="WARN_FILE" />-->
    <!--</root>-->
    <!--</springProfile>-->

</configuration>

启动gateway

此时我们的gateway服务应该只用3个重要的文件

  1. pom.xml
  2. Application.java
  3. bootstrap.yml
  4. logback-spring.xml

image.png

微服务配置

微服务目前需要做的是,注册到Nacos,并使用一个Nacos配置,实现一个基础的接口,返回指定数据信息。

微服务项目文件

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.13</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.fir</groupId>
    <artifactId>nacos</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>fir_java_nacos</name>
    <description>fir_java_nacos</description>
    <properties>
        <java.version>1.8</java.version>
        <alibaba.cloud.version>2021.0.5.0</alibaba.cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- nacos客户端依赖 -->
        <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-bootstrap</artifactId>
            <version>3.1.1</version>
        </dependency>

    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${alibaba.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Application.java

package com.fir.nacos;

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


@EnableDiscoveryClient
@SpringBootApplication
public class Application {


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

}

DemoController.java

package com.fir.nacos.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.HashMap;


/**
 * @author fir
 */
@Slf4j
@RestController
@RefreshScope
public class DemoController {

 
    /** 使用@value注解取值,它能取到值,但没有自动更新的功能 */
    @Value(value = "${aa}")
    private String aa;

    @Value(value = "${name}")
    private String name;


    @RequestMapping("/getValue")
    public HashMap<String, Object> getValue(String msg) {
        HashMap<String, Object> result = new HashMap<>();
        HashMap<String, Object> map = new HashMap<>();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long timeSleep = System.currentTimeMillis();
        String dateTime = sdf.format(timeSleep);

        String content = aa + "我是" + name + " 收到客户端消息:" + msg;

        map.put("value", aa);
        map.put("dateTime", dateTime);
        map.put("content", content);
        map.put("intValue", 120);
        map.put("doubleValue", 12.012);

        log.info("{} {} {}", name, timeSleep, aa);
        result.put("code", 200);
        result.put("msg", "操作成功");
        result.put("data", map);
        return result;
    }


    @RequestMapping("/get/value/body")
    public HashMap<String, Object> getValueBody(@RequestBody String msg) {
        HashMap<String, Object> result = new HashMap<>();
        HashMap<String, Object> map = new HashMap<>();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long timeSleep = System.currentTimeMillis();
        String dateTime = sdf.format(timeSleep);

        String content = aa + "我是" + name + " 收到客户端消息:" + msg;

        map.put("value", aa);
        map.put("dateTime", dateTime);
        map.put("content", content);
        map.put("intValue", 120);
        map.put("doubleValue", 12.012);

        log.info("{} {} {}", name, timeSleep, aa);
        result.put("code", 200);
        result.put("msg", "操作成功");
        result.put("data", map);
        return result;
    }
}

bootstrap.yml

server:
  port: 12009
spring:
  application:
    name: fir-node-two-dev
  cloud:
    # nacos.core.auth.caching.enabled=true 时,开启登录校验
    # 此时需要设置 username 与 password
    # nacos.core.auth.caching.enabled=false 时,不使用用户与密码
    nacos:
      discovery:
        server-addr: localhost:18884
        username: nacos
        password: nacos
        service: fir-node-two-dev
      config:
        server-addr: localhost:18884
        file-extension: yml
        username: nacos
        password: nacos
        group: DEFAULT_GROUP

# 引入logger日志相关配置
logging:
  config: classpath:logback-spring.xml

name: 子节点2-1号

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration  scan="true" scanPeriod="10 seconds">

  <!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->

  <contextName>logback</contextName>
  <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
  <property name="log.path" value="logs" />

  <!-- 彩色日志 -->
  <!-- 彩色日志依赖的渲染类 -->
  <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
  <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
  <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
  <!-- 彩色日志格式 -->
  <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>


  <!--输出到控制台-->
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>info</level>
    </filter>
    <encoder>
      <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
      <!-- 设置字符集 -->
      <charset>UTF-8</charset>
    </encoder>
  </appender>


  <!--输出到文件-->

  <!-- 时间滚动输出 level为 DEBUG 日志 -->
  <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!-- 正在记录的日志文件的路径及文件名 -->
    <file>${log.path}/log_debug.log</file>
    <!--日志文件输出格式-->
    <encoder>
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      <charset>UTF-8</charset> <!-- 设置字符集 -->
    </encoder>
    <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- 日志归档 -->
      <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>100MB</maxFileSize>
      </timeBasedFileNamingAndTriggeringPolicy>
      <!--日志文件保留天数-->
      <maxHistory>15</maxHistory>
    </rollingPolicy>
    <!-- 此日志文件只记录debug级别的 -->
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>debug</level>
      <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_info.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 WARN 日志 -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_warn.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>


    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/log_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
        以及指定<appender>。<logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
              如果未设置此属性,那么当前logger将会继承上级的级别。
        addtivity:是否向上级logger传递打印信息。默认是true。
    -->
    <!--<logger name="org.springframework.web" level="info"/>-->
    <!--<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>-->
    <!--
        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
        第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
        第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
     -->


    <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        不能设置为INHERITED或者同义词NULL。默认是DEBUG
        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
    -->

    <!--开发环境:打印控制台-->
    <springProfile name="dev">
        <logger name="com.nmys.view" level="debug"/>
    </springProfile>

    <root level="info">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="DEBUG_FILE" />
        <appender-ref ref="INFO_FILE" />
        <appender-ref ref="WARN_FILE" />
        <appender-ref ref="ERROR_FILE" />
    </root>

    <!--生产环境:输出到文件-->
    <!--<springProfile name="pro">-->
    <!--<root level="info">-->
    <!--<appender-ref ref="CONSOLE" />-->
    <!--<appender-ref ref="DEBUG_FILE" />-->
    <!--<appender-ref ref="INFO_FILE" />-->
    <!--<appender-ref ref="ERROR_FILE" />-->
    <!--<appender-ref ref="WARN_FILE" />-->
    <!--</root>-->
    <!--</springProfile>-->

</configuration>

启动微服务

此时我们的gateway服务应该只用4个重要的文件

  1. pom.xml
  2. Application.java
  3. bootstrap.yml
  4. DemoController.yml
  5. logback-spring.xml

image.png

最终

检查服务是否注册

此时我们将在Nacos中看到有两个服务已经注册
image.png

测试转发

此时我们想访问

http://localhost:12009/getValue

image.png
则通过gateway访问

http://localhost:51001/tick/getValue

image.png

常见错误

Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better!

按理说不可能报错,看这个帖子的人最少都已经安装了JDK以及配置了环境变量。
没有安装的见该文章Java1.8安装以及设置环境变量。安装,下载(手把手教,最全教程)_java-1.8-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/484123.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用pandas进行数据清洗

采集到原始的数据中会存在一些噪点数据&#xff0c;噪点数据是对分析无意义或者对分析起到偏执作用的数据。如何清洗&#xff1a; 清洗空值/缺失值清洗重复值清洗异常值 import pandas as pd from pandas import DataFrame,Series import numpy as np pandas处理空值操作 i…

ppp实验

拓扑图 实验步骤 配置IP地址及创建mp逻辑口 [R1]int ser 3/0/0 [R1-Serial3/0/0]ip add 192.168.1.1 24 [R1-Serial3/0/0] [R2]int se3/0/0 [R2-Serial3/0/0]ip add 192.168.1.2 24 [R2-Serial3/0/0]int mp [R2-Serial3/0/0]int mp-g [R2-Serial3/0/0]int mp-group 0…

中国气象局发布大地磁暴预警:空间站轨道或受影响

什么是地磁暴&#xff1f; 地磁暴作为最典型的太阳爆发活动&#xff0c;一次地磁暴是一次日冕物质抛射过程&#xff0c;能将数以亿吨计的太阳物质以数百千米每秒的高速抛离太阳表面。 不光是巨大质量与速度汇聚成的动能&#xff0c;它们还携带着太阳强大的磁场能&#xff0c;一…

前端基础篇-前端工程化 Vue 项目开发流程(环境准备、Element 组件库、Vue 路由、项目打包部署)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 环境准备 1.1 安装 NodeJs 1.2 验证 NodeJs 环境变量 1.3 配置 npm 的全局安装路径 1.4 切换 npm 的淘宝镜像( npm 使用国内淘宝镜像的方法(最新) ) 1.5 查看镜像…

406. 根据身高重建队列(力扣LeetCode)

文章目录 406. 根据身高重建队列题目描述贪心算法代码 406. 根据身高重建队列 题目描述 假设有打乱顺序的一群人站成一个队列&#xff0c;数组 people 表示队列中一些人的属性&#xff08;不一定按顺序&#xff09;。每个 people[i] [hi, ki] 表示第 i 个人的身高为 hi &…

tabs自定义样式

使用el-tabs 去修改样式的话比较麻烦&#xff0c;索性直接用div来制作。 <div class"contain"><div class"tab_wrap"><div :class"[skew, first, active 1 ? isActive: ]" click"tabClick(1)"><span class&quo…

HTTP --- 下

目录 1. HTTP请求方式 1.1. HTML 表单 1.2. GET && POST方法 1.2.1. 用 GET 方法提交表单数据 1.2.2. 用 POST 方法提交表单数据 1.2.3. 总结 1.3. 其他方法 2. HTTP的状态码 2.1. 重定向 2.1.1. 临时重定向 && 永久重定向 2.1.2. 302 &&…

3 Spring之DI详解

5&#xff0c;DI相关内容 前面我们已经完成了bean相关操作的讲解&#xff0c;接下来就进入第二个大的模块DI依赖注入&#xff0c;首先来介绍下Spring中有哪些注入方式? 我们先来思考 向一个类中传递数据的方式有几种? 普通方法(set方法)构造方法 依赖注入描述了在容器中建…

19.严丝合缝的文明——模板方法模式详解

“项目评审的节点又快到了&#xff0c;PPT你写了没&#xff1f;” “Oops&#xff0c;忘了&#xff0c;有模板没&#xff1f;给我一份” 概述 模板&#xff0c;一个频繁出现在办公室各类角色口中的词&#xff0c;它通常意味着统一、高效、经验和优质。各项汇报因为PPT的模板变…

trinus 3d打印机安装调试到成功打印3-没有热床模型脱落底床不粘模型翘边错位

由于没有自带热肠&#xff0c;改装的话需要额外购买配套的热床。但是如果手头没有的话&#xff0c;那只能使用原厂赠送的两张美文纸。美纹纸很容易用破&#xff0c;尤其是喷头可能会划破。另外拆模型的时候会引起气泡。 于是翘边和模型脱落就成了家常便饭。 这些问题的根源都在…

C#学习笔记1:C#基本文件结构与语法

现在开始我的C#学习之路吧&#xff0c;这也许不适合0编程基础的人看&#xff0c;因为我会C语言了&#xff0c;笔记做的可能有思维上的跳跃&#xff0c;如果0基础可能会觉得有些地方转折得莫名奇妙&#xff0c;但我的学习笔记实操还是比较多的&#xff0c;基本都是真实运行程序结…

七.(1)堆排序--前传

目录 七.(1)堆排序--前传 20-堆排序前传-树的基础知识 根节点 叶子节点 树的深度(高度) 树的 度 孩子节点/父亲节点 子树 21.堆排序前传-二叉树的基础知识 二叉树的存储方式: 22-堆排序前传-堆和堆的向下调整 什么是堆? 堆的向下调整性质 23-堆排序的过程演示 七…

Android Preference简单介绍

Android Preference简单介绍 文章目录 Android Preference简单介绍一、前言二、Preference 简单介绍二、PreferenceScreen和SwitchPreference 简单示例2、相关demo代码示例&#xff08;1&#xff09;SettingsActivity.Java&#xff08;2&#xff09;layout\settings_activity.x…

redis复习笔记07(小滴课堂)

在线教育-天热销视频榜单实战-List数据结构设计 我们先随机获取整个列表的内容。 我们模拟一个去添加数据的接口&#xff1a; 运行&#xff1a; 我们可以看到这里的数据。 我们现在启动我们的应用和controller&#xff1a; 就可以查到我们的数据了。 我们进行人工操作位&…

基于unbantu的nginx的配置

目录 前言: 1.安装nginx并进行测试 1.1使用nginx -v 命令查看版本 1.2开启服务 查看端口 1.3测试 2.nginx的静态资源访问配置 2.1创建静态资源存放的目录 2.2写入目录中测试文件对应的内容 2.3修改配置文件 2.4 测试 3.虚拟主机配置 3.1创建目录 3.2写入测试…

PPP MP配置

一.添加接口 每个路由器中添加2SA接口 二.配置IP地址 1.在r2和r3上创建MP [r2]int Mp-group 0/0/0 [r2-Mp-group0/0/0] [r3]int Mp-group 0/0/0 [r3-Mp-group0/0/0] 2.把1中上的接口加入上一步创建的MP [R2]int Serial 3/0/1 [R2-Serial3/0/1]ppp mp Mp-group 0/0/0 [R2]i…

Learn OpenGL 24 点光源阴影

点光源阴影 上个教程我们学到了如何使用阴影映射技术创建动态阴影。效果不错&#xff0c;但它只适合定向光&#xff0c;因为阴影只是在单一定向光源下生成的。所以它也叫定向阴影映射&#xff0c;深度&#xff08;阴影&#xff09;贴图生成自定向光的视角。 本节我们的焦点是…

整数和浮点数分别在内存中的存储

目录 一、整数在内存中的存储二、浮点数在内存中的存储2.1存储2.2取2.2.1 E不全为0或者不全为12.2.2 E全为02.2.3 E全为1 三、题目解析 一、整数在内存中的存储 对于整形来说&#xff1a;数据存放内存中其实存放的是补码。 原因在于&#xff0c;使用补码&#xff0c;可以将符号…

Redis 6和7:探索新版本中的新特性

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! Redis&#xff0c;作为开源的内存数据结构存储系统&#xff0c;以其高性能、丰富的数据结构和广泛的应用场景而深受开发者喜爱。随…

面试题:Java中的类加载器

1. 什么是类加载器&#xff0c;类加载器有哪些? 要想理解类加载器的话&#xff0c;务必要先清楚对于一个Java文件&#xff0c;它从编译到执行的整个过程。 类加载器&#xff1a;用于装载字节码文件(.class文件)运行时数据区&#xff1a;用于分配存储空间执行引擎&#xff1a;…