crm开发定制微服务 Spring Cloud Gateway 网关 基础配置

官网:

中文文档:

介绍:

crm开发定制网关就是当前的统一入口
crm开发定制通常在微服务项目中,crm开发定制只有网关项目是暴露在网络里的,crm开发定制其他服务一般都是在内网里,
crm开发定制用户访问网关,crm开发定制网关根据访问的路径,crm开发定制来进行路由
Gateway 网关也是微服务的一部分,需要将项目注册到Nacos
因为某一个服务可能存在多台服务器,所以也需要负载均衡依赖

依赖项

<!--Gateway网关依赖--><dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--网关负载均衡依赖--><dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><!--Nacos依赖--><dependency>  <groupId>com.alibaba.cloud</groupId>  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

纯yml文件配置的方式实现路由(包含Nacos注册与Gateway配置)

spring:  application:    name: gateway  cloud:    nacos:      discovery:        # 设置nacos服务器的地址        server-addr: localhost:8848        # 默认为true是临时实例, 改为 false 就是永久实例        ephemeral: true    gateway:      #下面编写Gateway路由配置      routes:          #当前路由名称        - id: gateway-beijing          #当匹配路由的路径时,设置访问的服务器(Nacos里注册的服务器,在那个项目的spring.application.name设置里)          #lb是loadbalancer负载均衡的缩写          uri: lb://beijing          #断言 既满足条件时做某些事情          predicates:              #当请求路径以/bj/开头时,就会路由到上面设置的  lb://beijing  服务器            - Path=/bj/**        - id: gateway-shanghai          uri: lb://shanghai          predicates:            - Path=/sh/**
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

编写配置类的方式实现配置(此种方式,配置文件里只配置Nacos注册中心即可)

spring:  application:    name: gateway  cloud:    nacos:      discovery:        # 设置nacos服务器的地址        server-addr: localhost:8848
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
package cn.tedu.gateway.config;import org.springframework.cloud.gateway.route.RouteLocator;import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class GatewayConfiguration {    @Bean    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();        routes                //名称为gateway-beijing的路由,匹配地址 /bj/** 使用  Nacos  里的 beijing 去处理请求 lb为负载均衡                .route("gateway-beijing", r -> r.path("/bj/**").uri("lb://beijing"))                .route("gateway-shanghai", r -> r.path("/sh/**").uri("lb://shanghai"))                            .route("gateway-after", r ->                    //匹配路径为 /show                    r.path("/show")                    //多个断言之间,使用and方法连接                    .and()                    //断言时间,只能在此时间后访问                    .after(ZonedDateTime.parse("2022-08-25T10:00:00+08:00[Asia/Shanghai]"))                    .and()                    //断言查询参数,必须包含age,如  /show?age=1                    .query("age")                    //设置过滤器,在过滤器内添加请求参数,那么实际控制器收到的请求为: /show?age=1&name=tom                    .filters(f -> f.addRequestParameter("name", "tom"))                    //使用shanghai去处理请求                    .uri("lb://shanghai")                 )                //将路径为 /personal 的请求,转到石墨文档,石墨文档收到请求后,请求地址为: https://shimo.im/personal                .route("gateway-shimo", r -> r.path("/personal").uri("https://shimo.im"))                .build();        return routes.build();    }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

动态路由(默认关闭)

开启方式:在配置文件中设置spring.cloud.gateway.discovery.locator.enabled=true

spring:  application:    name: gateway  cloud:    nacos:      discovery:        # 设置nacos服务器的地址        server-addr: localhost:8848        # 默认为true是临时实例, 改为 false 就是永久实例        ephemeral: true    gateway:      discovery:        locator:          #开启动态路由          enabled: true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

开启后,无需编写配置类或yaml内的配置
访问路由时,需要带上Nacos里注册的名称

如,假设
Gateway网关的端口为9000
北京服务器端口为9001(Nacos注册名为beijing)
上海服务器端口为9002(Nacos注册名为shanghai)
2个服务器同时都暴露了一个 /xx/show 的接口

原访问地址:

http://localhost:9001/bj/showhttp://localhost:9002/sh/show
  • 1
  • 2

通过网关的访问地址:

http://localhost:9000/beijing/bj/show   >>等价于>>   http://localhost:9001/bj/showhttp://localhost:9000/shanghai/sh/show	>>等价于>>   http://localhost:9002/sh/show
  • 1
  • 2

其中,地址中的 **shanghai/beijing **即为Nacos里,注册服务器的名称,请求会被路由到相应的服务器

注:动态路由与手动设置配置文件或编写配置类可以同时存在,并且同时生效

在网关中使用swagger/knife4j来测试其他服务的接口

在pom文件中添加swagger/knife4j依赖

<dependency>  <groupId>com.github.xiaoymin</groupId>  <artifactId>knife4j-spring-boot-starter</artifactId></dependency>
  • 1
  • 2
  • 3
  • 4

添加以下3个类…添加后,
访问 http://网关地址:网关端口/服务名称/doc.html 来访问
如下,其中 nacos-stock 是注册到Nacos的一个服务名称

http://localhost:19000/nacos-stock/doc.html
  • 1

控制器类

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import reactor.core.publisher.Mono;import springfox.documentation.swagger.web.*;import java.util.Optional;@RestController@RequestMapping("/swagger-resources")public class SwaggerController {    @Autowired(required = false)    private SecurityConfiguration securityConfiguration;    @Autowired(required = false)    private UiConfiguration uiConfiguration;    private final SwaggerResourcesProvider swaggerResources;    @Autowired    public SwaggerController(SwaggerResourcesProvider swaggerResources) {        this.swaggerResources = swaggerResources;    }    @GetMapping("/configuration/security")    public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {        return Mono.just(new ResponseEntity<>(            Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));    }    @GetMapping("/configuration/ui")    public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {        return Mono.just(new ResponseEntity<>(            Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));    }    @GetMapping("")    public Mono<ResponseEntity> swaggerResources() {        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

配置类

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.cloud.gateway.route.RouteLocator;import org.springframework.stereotype.Component;import springfox.documentation.swagger.web.SwaggerResource;import springfox.documentation.swagger.web.SwaggerResourcesProvider;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Set;@Componentpublic class SwaggerProvider implements SwaggerResourcesProvider {    /**     * 接口地址     */    public static final String API_URI = "/v2/api-docs";    /**     * 路由加载器     */    @Autowired    private RouteLocator routeLocator;    /**     * 网关应用名称     */    @Value("${spring.application.name}")    private String applicationName;    @Override    public List<SwaggerResource> get() {        //接口资源列表        List<SwaggerResource> resources = new ArrayList<>();        //服务名称列表        List<String> routeHosts = new ArrayList<>();        // 获取所有可用的应用名称        routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)                .filter(route -> !applicationName.equals(route.getUri().getHost()))                .subscribe(route -> routeHosts.add(route.getUri().getHost()));        // 去重,多负载服务只添加一次        Set<String> existsServer = new HashSet<>();        routeHosts.forEach(host -> {            // 拼接url            String url = "/" + host + API_URI;            //不存在则添加            if (!existsServer.contains(url)) {                existsServer.add(url);                SwaggerResource swaggerResource = new SwaggerResource();                swaggerResource.setUrl(url);                swaggerResource.setName(host);                resources.add(swaggerResource);            }        });        return resources;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

过滤器类

import org.springframework.cloud.gateway.filter.GatewayFilter;import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import org.springframework.web.server.ServerWebExchange;@Componentpublic class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {    private static final String HEADER_NAME = "X-Forwarded-Prefix";    private static final String URI = "/v2/api-docs";    @Override    public GatewayFilter apply(Object config) {        return (exchange, chain) -> {            ServerHttpRequest request = exchange.getRequest();            String path = request.getURI().getPath();            if (!StringUtils.endsWithIgnoreCase(path,URI )) {                return chain.filter(exchange);            }            String basePath = path.substring(0, path.lastIndexOf(URI));            ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();            ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();            return chain.filter(newExchange);        };    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

注意: 由于Spring Boot,Spring Cloud Gateway都带有spring-boot-starter-web依赖,但是前者使用Tomcat,后者使用Netty,会导致冲突,项目无法启动

解决办法有3个

1. 在配置文件中,指定spring.main.web-application-type=reactive

spring:  main:    web-application-type: reactive
  • 1
  • 2
  • 3

2. 添加spring-boot-starter-web依赖时,排除Tomcat

<!-- web实例 --><dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId>  <exclusions>    <exclusion>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-tomcat</artifactId>    </exclusion>  </exclusions></dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3.不添加spring-boot-starter-web依赖,只添加Spring Cloud Gateway依赖

<!-- web实例 --><dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId></dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

达内:lzy

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发