springcloud nacos gateway 基础搭建详细步骤

记录搭建详细过程

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

1:搭建主项目子项目

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

springcloud nacos gateway 基础搭建详细步骤_第1张图片

创建maven项目

springcloud nacos gateway 基础搭建详细步骤_第2张图片

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

springcloud nacos gateway 基础搭建详细步骤_第3张图片

然后修改pom.xml

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

然后增加依赖内容

注意:

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

dependencyManagement 与 dependencies 区别 :

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

承)

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

赖。

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

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

scope 都读取自父 pom 。

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



    4.0.0

    org.example
    ceshiwanzheng
    1.0-SNAPSHOT
    pom

    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.3.RELEASE
    
    
        Greenwich.SR1
        2.7.0
    
    
        
            org.springframework.boot
            spring-boot-autoconfigure
        
        
            org.projectlombok
            lombok
        
        
            org.springframework.boot
            spring-boot-starter
            
                
                
                    org.springframework.boot
                    spring-boot-starter-logging
                
            

        
    

    
    
        
            org.springframework.boot
            spring-boot-dependencies
            2.1.6.RELEASE
            pom
            import
        
        
            com.alibaba.cloud
            spring-cloud-alibaba-sentinel
            2.1.1.RELEASE
            pom
            import
        

        
            com.alibaba.cloud
            spring-cloud-alibaba-dependencies
            2.1.0.RELEASE
            pom
            import
        

        
            org.springframework.cloud
            spring-cloud-starter-openfeign
            2.1.1.RELEASE
            pom
            import
        

        
                org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.0.1
        
    
    

主项目就算创建完成了。

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

创建时候选择spring创建,

springcloud nacos gateway 基础搭建详细步骤_第4张图片

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

springcloud nacos gateway 基础搭建详细步骤_第5张图片

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

springcloud nacos gateway 基础搭建详细步骤_第6张图片

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

springcloud nacos gateway 基础搭建详细步骤_第7张图片

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

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

provider

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

com.example

provider

0.0.1-SNAPSHOT

provider

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

org.example

ceshiwanzheng

1.0-SNAPSHOT



    4.0.0

    com.example
    provider
    0.0.1-SNAPSHOT
    provider
    Demo project for Spring Boot

    
        org.example
        ceshiwanzheng
        1.0-SNAPSHOT
    
    
        8
        8
    
    
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
        
            commons-codec
            commons-codec
            1.11
        
        
        
            io.github.openfeign
            feign-httpclient
            10.1.0
        

        
            cn.hutool
            hutool-all
            5.8.5
        
        
            org.springframework.boot
            spring-boot-starter-jdbc
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            mysql
            mysql-connector-java
            8.0.11
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.4.3
        

        
            com.baomidou
            mybatis-plus-core
            3.4.3.1
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            com.baomidou
            mybatis-plus-generator
            3.5.3
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-config
        
        
            com.baomidou
            mybatis-plus
            3.5.2
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            
        
        
            com.baomidou
            mybatis-plus-extension
            3.5.2
        
        
            org.springframework.boot
            spring-boot-starter-logging
        







        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
            com.alibaba.cloud
            spring-cloud-alibaba-sentinel
        
        
            redis.clients
            jedis
            2.9.1
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.apache.commons
            commons-pool2
            2.9.0
        
        
        
            org.projectlombok
            lombok
            true
            LATEST
        
        
            junit
            junit
            4.12
        
        
            com.alibaba
            druid
            1.2.3
        
    
    

    

    
        
            
                src/main/java
                
                    **/*.xml
                
            
            
                src/main/resources
                
                    **/**
                
                false
            
        
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    true
                
            
        
    


然后创建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.复制这个地址到服务器上就能用

springcloud nacos gateway 基础搭建详细步骤_第8张图片

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

springcloud nacos gateway 基础搭建详细步骤_第9张图片

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

springcloud nacos gateway 基础搭建详细步骤_第10张图片

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

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

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

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

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

     
            org.springframework.cloud
            spring-cloud-starter-gateway
        

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的代码结构如下:

springcloud nacos gateway 基础搭建详细步骤_第11张图片

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

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



    @Override
    public Mono 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 cachedFlux = Flux.defer(() -> {
                            DataBuffer buffer = exchange.getResponse().bufferFactory()
                                    .wrap(bytes);
                            return Mono.just(buffer);
                        });

                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                exchange.getRequest()) {
                            @Override
                            public Flux 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 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 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 writeWith(Publisher body) {
                if (body instanceof Flux) {
                    Flux fluxBody = (Flux) 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 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 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的内容了。

你可能感兴趣的:(spring,java,spring,cloud)