springcloud nacos gateway 基础搭建详细步骤

记录搭建详细过程

使用一个主项目管理依赖,其他都是子项目

1:搭建主项目子项目

首先创建主项目,选择的是maven.直接file-new-project创建,

创建maven项目

创建完成后是个简单的maven项目,删掉src文件夹变成了:

然后修改pom.xml

首先把<packaging></packaging>修改成<packaging>pom</packaging>因为这主项目只是个管理pom文件的。

然后增加依赖内容

注意:

dependencyManagement( 管理 jar 包的版本 , 让子项目中引用一个依赖而不用显示的列出版本号 )

dependencyManagement 与 dependencies 区别 :

dependencies 即使在子项目中不写该依赖项 , 那么子项目仍然会从父项目中继承该依赖项(全部继

承)

dependencyManagement 里只是声明依赖 , 并不实现引入 , 因此子项目需要显示的声明需要用的依

赖。

如果不在子项目中声明依赖 , 是不会从父项目中继承下来的。

只有在子项目中写了该依赖项 , 并且没有指定具体版本 , 才会从父项目中继承该项 , 并且 version 和

scope 都读取自父 pom 。

另外如果子项目中指定了版本号 , 那么会使用子项目中指定的 jar 版本。

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>ceshiwanzheng</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
    </parent>
    <properties>
        <spring-cloud-version>Greenwich.SR1</spring-cloud-version>
        <swagger2.version>2.7.0</swagger2.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <!--排除spring官方的注解,采用log4j2作为日志输出-->
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>

        </dependency>
    </dependencies>

    <dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.6.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel</artifactId>
            <version>2.1.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.1.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.1.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>

        <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>
    </dependencies>
    </dependencyManagement>
</project>

主项目就算创建完成了。

然后创建子项目,对着主项目,右键New-Module 这样创建就是子项目:

创建时候选择spring创建,

注意:Type是maven。 java Version选择自己的,反正我的Java是1.8的

选择依赖的必须选择spring Web,不然后面会有springboot启动类没有run的错误

然后创建出的文件夹如下:provider项目就是子项目

然后修改主项目和子项目的pom

主项目修改,把子项目provider加入到主项目中

<modules>

<module>provider</module>

</modules>

子项目修改pom,修改较多,我一次性把所有可能需要的都加进去了,复制这个pom。修改一下项目信息

<groupId>com.example</groupId>

<artifactId>provider</artifactId>

<version>0.0.1-SNAPSHOT</version>

<name>provider</name>

和parent信息就可以直接使用了,parent就是主项目的信息。

<parent>

<groupId>org.example</groupId>

<artifactId>ceshiwanzheng</artifactId>

<version>1.0-SNAPSHOT</version>

</parent>

<?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>

    <groupId>com.example</groupId>
    <artifactId>provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>provider</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.example</groupId>
        <artifactId>ceshiwanzheng</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.11</version>
        </dependency>
        <!-- 使用 openfeign 自家的 feign httpclient 代替 Apache httpclient 发送请求 -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>10.1.0</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-core</artifactId>
            <version>3.4.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.3</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <!--            <version>LATEST</version>-->
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-extension</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </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-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.9.0</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.3</version>
        </dependency>
    </dependencies>
    <dependencyManagement>

    </dependencyManagement>

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/**</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <includeSystemScope>true</includeSystemScope>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

然后创建bootstrap.yaml。因为nacos是先读取boostrap.yaml里的配置再读取applicaion.yaml。在使用配置中心的时候application.yaml可以自己写也可以直接配置在nacos的配置中心里面。下面是bootstrap.yaml 下面的配置都是与在nacos操作页面上进行配置的一致。在操作页面配置后需要进行对应更改。

server:
  port: 8888

spring:
  application:
    name: provider
  profiles:
    active: dev # 环境,自己对应    
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848    #注册中心地址
      config:
        server-addr: 127.0.0.1:8848   #配置中心地址
        file-extension: yaml  #后缀名
        group: devGroup      #分组,自己对应 
        namespace: c38781c7-c36d-412a-9d8e-43b7547d4ae8  #命名空间的id,自己对应 

我的applicaion

spring:

  resources:
    static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:./../images

  datasource:

    url: jdbc:mysql://127.0.0.1:3306/mre?&serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
    
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
   
    password: chengdu2020
  
    druid:
      max-active: 200
      # 超过时间限制是否回收
      remove-abandoned: true
      # 超时时间;单位为秒。180秒=3分钟
      remove-abandoned-timeout: 180
      # 关闭abanded连接时输出错误日志
      log-abandoned: true
mybatis-plus:
  configuration:
    map-underscore-to-camel-case: false #开启数据库下划线字段映射为驼峰
    log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl #开启sql控制台打印
#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

然后要正确启动的话就需要把启动类加上@EnableDiscoveryClient 这是服务发现

@EnableDiscoveryClient

@SpringBootApplication
public class ProviderApplication {

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

}

最后。获取配置中心的值的例子

写个controller用于测试

@RestController("/provider")
@Slf4j
@RefreshScope //动态刷新
public class TestController {
    @Value("${config.info}")
    private String info;     //该属性值是从nacos配置中心拉取到的配置

    @GetMapping("/testConfig")
    public String testConfig(){
        return info;
    }

}

如图:获取config.info的值就和获取本地yml里面的值是一样的方式。

而配置这个值就需要打开nacos管理中心,首先是下载nacos。我下载的是windows版本。然后运行nacos.复制这个地址到服务器上就能用

打开网址登陆,默认账号密码都是nacos 登陆后如下:首先是配置命名空间,然后在配置列表里就可以点进对应配置命名空间的yaml ,这里的命名空间后面这串代码就是要填写在bootstrap.yaml里的命名空间id 然后点击+ 增加配置文件,

配置的属性就要和boostrap.yaml里对应了

到这一步nacos的配置中心和注册中心就算使用完成了。

上面完成的是nacos的配置。。接下来是完成gateWay的

gateway是网关。最常见的作用是统一访问路径。如:多个服务的端口号是不一样的。对于前端来说访问不同服务就得加不同的端口号地址。 使用gateway 那么访问的端口号就是gateway得的端口号

在建立好前面的provider之后。创建一个服务是gateway

在pom.xml几乎和provider一样。只是多加了

     <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

boostrap.xml

server:
  port: 9999

spring:
  application:
    name: gateway
  profiles:
    active: dev # 环境
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.150.1:8848    #注册中心地址
      config:
        server-addr: 192.168.150.1:8848   #配置中心地址
        file-extension: yaml  #后缀名
        group: devGroup      #分组
        namespace: c38781c7-c36d-412a-9d8e-43b7547d4ae8  #命名空间的id
    gateway:
      discovery:
        locator:
          enabled: true  # 让gateway可以发现nacos中的微服务
      routes: # 路由数组,路由就是指定当请求满足什么条件的时候,转到 哪个微服务
        - id: provider  # 路由的Id,没有固定规则,但要求唯一,建议配合服务名
          #          uri: http://localhost:9083 # 匹配后,请求转发到的地址
          uri: lb://provider # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          predicates: # 断言:就是路由转发要满足的条件
            - Path=/provider/** # 当请求路径满足Path指定的规则时,才进行路由转发

        - id: consumer
          #          uri: http://localhost:9084
          uri: lb://consumer # lb 指的是负载均衡,后面跟的是具体微服务在nacos中的标识
          predicates:
            - Path=/prefix/consumer/**
          filters: # 过滤器(在请求传递过程中,对请求做一些手脚)
            - StripPrefix=1  # 在请求转发之前去掉一层路径,http://localhost:9081/prefix/consumer/service,实际请求会去掉prefix

application.yaml和provider一样就行

启动类也一样就行,

然后测试。访问localhost:9999/provider/testConfig 就可以实际访问到provider服务对应的方法了。

网关弄好后可以做一些事情,比如。gateway里写filter获取request和response的信息

这里我把我完整代码贴出来 gateway的代码结构如下:

1:HttpRequestFilter 获取request的filter. 因为多个filter获取数据其实会出现request只能访问一次的情况。

这个代码不存在这个问题,可以直接使用。



    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

        String method = request.getMethodValue();
        String contentType = request.getHeaders().getFirst("Content-Type");
        if ("POST".equals(method)) {
            return DataBufferUtils.join(exchange.getRequest().getBody())
                    .flatMap(dataBuffer -> {
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        try {
                            String bodyString = new String(bytes, "utf-8");
                            System.out.println(bodyString);
                            System.out.println(request.getPath());
                            System.out.println(request.getURI());




                            log.info(bodyString);//打印请求参数
                            exchange.getAttributes().put("POST_BODY", bodyString);
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        DataBufferUtils.release(dataBuffer);
                        Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                            DataBuffer buffer = exchange.getResponse().bufferFactory()
                                    .wrap(bytes);
                            return Mono.just(buffer);
                        });

                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                exchange.getRequest()) {
                            @Override
                            public Flux<DataBuffer> getBody() {
                                return cachedFlux;
                            }
                        };
                        return chain.filter(exchange.mutate().request(mutatedRequest)
                                .build());
                    });
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -200;
    }
}

RequestUtil是用于解析request的


import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import reactor.core.publisher.Flux;

import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author mjw
 * @date 2020/3/30
 */
public class RequestUtil
{
    /**
     * 读取body内容
     * @param serverHttpRequest
     * @return
     */
    public static String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest){
        //获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        StringBuilder sb = new StringBuilder();

        body.subscribe(buffer -> {
            byte[] bytes = new byte[buffer.readableByteCount()];
            buffer.read(bytes);
//            DataBufferUtils.release(buffer);
            String bodyString = new String(bytes, StandardCharsets.UTF_8);
            sb.append(bodyString);
        });
        return formatStr(sb.toString());
    }

    /**
     * 去掉空格,换行和制表符
     * @param str
     * @return
     */
    private static String formatStr(String str){
        if (str != null && str.length() > 0) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(str);
            return m.replaceAll("");
        }
        return str;
    }
}

HttpResponseFilter是获取response的


import java.nio.charset.StandardCharsets;
import java.util.List;

@Slf4j
@Component
public class HttpResponseFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().toString();
        ServerHttpResponse originalResponse = exchange.getResponse();
        System.out.println(originalResponse.isCommitted());
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
                        DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                        DataBuffer join = dataBufferFactory.join(dataBuffer);
                        byte[] content = new byte[join.readableByteCount()];
                        join.read(content);
                        //释放掉内存
                        DataBufferUtils.release(join);
                        String s = new String(content, StandardCharsets.UTF_8);
                        List<String> strings = exchange.getResponse().getHeaders().get(HttpHeaders.CONTENT_ENCODING);

                            s = new String(content, StandardCharsets.UTF_8);
                            System.out.println("响应信息"+s);
                        log.info("bodyString: {}", s);//打印请求响应值
                        return bufferFactory.wrap(content);
                    }));
                }
                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }
    @Override
    public int getOrder() {
        return -200;
    }
}

AuthGlobalFilter是想用于登陆相关的


import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;

import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Mono;

/**
 * @author mjw
 * @date 2020/3/24
 */
@Component
@Slf4j
public class AuthGlobalFilter implements GlobalFilter, Ordered
{
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    {
        String bodyContent = RequestUtil.resolveBodyFromRequest(exchange.getRequest());
        System.out.println("你好不好啊"+bodyContent);
        // TODO 身份认证相关逻辑

        return chain.filter(exchange.mutate().build());
    }

    @Override
    public int getOrder()
    {
        return -100;
    }
}

所有代码就写完了

我们再回到provider这个服务

因为要获取body的原因。我改了controller的testConfig方法

这样。前端postman测试。就可以使用 raw application/json 这样的方式传过来。ConditionDto是随意写的用于测试的实体类。

   @PostMapping("/testConfig")
    public String testConfig ( @RequestBody ConditionDto request){
        System.out.println(request.getCity());

        return info;
    }

ConditionDto.java

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ConditionDto {
private  String city;
private String  name;
}

就这样。在使用postman访问http://localhost:9999/provider/testConfig的时候就可以获取到body的内容了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值