gateway整合nacos实现动态路由和swagger的接口文档

gateway整合nacos实现动态路由和swagger的接口文档

一、配置nacos实现动态路由

二、整合swagger

1.1. 配置naos的config

nacos依赖 版本<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!-- spring cloud nacos discovery -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableDiscoveryClient
public class NacosDiscoveryConfiguration {
}

1.2.配置nacos路由数据源


import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * nacos路由数据源
 *
 */
@Slf4j
public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {

    private String routerDataId;

    private ApplicationEventPublisher publisher;

    private NacosConfigProperties nacosConfigProperties;

    public NacosRouteDefinitionRepository(String routerDataId, ApplicationEventPublisher publisher, NacosConfigProperties nacosConfigProperties) {
        this.routerDataId = routerDataId;
        this.publisher = publisher;
        this.nacosConfigProperties = nacosConfigProperties;
        addListener();
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        try {
            String content = nacosConfigProperties.configServiceInstance().getConfig(routerDataId, nacosConfigProperties.getGroup(), 5000);
            List<RouteDefinition> routeDefinitions = getListByStr(content);
            return Flux.fromIterable(routeDefinitions);
        } catch (NacosException e) {
            log.error("getRouteDefinitions by nacos error", e);
        }
        return Flux.fromIterable(Collections.EMPTY_LIST);
    }

    /**
     * 添加Nacos监听
     */
    private void addListener() {
        try {
            nacosConfigProperties.configServiceInstance().addListener(routerDataId, nacosConfigProperties.getGroup(), new Listener() {
                public Executor getExecutor() {
                    return null;
                }

                public void receiveConfigInfo(String configInfo) {
                    publisher.publishEvent(new RefreshRoutesEvent(this));
                }
            });
        } catch (NacosException e) {
            log.error("nacos-addListener-error", e);
        }
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return null;
    }

    /**
     * 解析路由
     * @param content
     * @return
     */
    private List<RouteDefinition> getListByStr(String content) {
        if (StringUtils.isNotEmpty(content)) {
            return JSONObject.parseArray(content, RouteDefinition.class);
        }
        return new ArrayList<>(0);
    }
}

1.3.动态路由配置


import com.alibaba.cloud.nacos.NacosConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 动态路由配置
 */
@Configuration
public class DynamicRouteConfig {
    @Autowired
    private ApplicationEventPublisher publisher;

    @Value("${spring.cloud.nacos.config.router-data-id:gateway-router.json}")
    private String routerDataId;

    /**
     * Nacos实现方式
     */
    @Configuration
    public class NacosDynRoute {
        @Autowired
        private NacosConfigProperties nacosConfigProperties;

        @Bean
        public NacosRouteDefinitionRepository nacosRouteDefinitionRepository() {
            return new NacosRouteDefinitionRepository(routerDataId, publisher, nacosConfigProperties);
        }
    }
}

1.4.bootstrap.yml文件的配置

spring:
  cloud:
    # nacos-配置
    nacos:
      config:
        # 是否开启配置中心,默认true
        enabled: true
        server-addr: ip地址:8848
        file-extension: yaml
        encode: UTF-8
        group: FINANCE
        router-data-id: gateway-router.json #nacos的配置中心的配置文件名
      discovery:
        server-addr: ip地址:8848
        group: FINANCE  #组名,与微服务组名一致

#可以访问你在配置中心配置的路由 
#访问路径:IP地址:1111/actuator/gateway/routes
management:
  endpoints:
    health:
      show-details: always
    web:
      exposure:
        include: '*'

#日志文件的配置
logging:
  level:
    root: WARN
    com.woniu: DEBUG
  pattern:
    console: "${CONSOLE_LOG_PATTERN:\
      %clr(${LOG_LEVEL_PATTERN:%5p}) \
      %clr(|){faint} \
      %clr(%logger{39}){cyan} \
      %clr(:){faint} \
      %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}}"

1.5.nacos配置中的配置文件
访问地址:http://ip地址:8848/nacos
添加配置文件
配置详情
配置路由规则

[{
    "filters": [{
         "args": {
            "parts": "0"
        },
        "name": "StripPrefix"
    }],
    "id": "order_route",
    "order": 0,
    "predicates": [{
        "args": {
            "pattern": "/order/**"
        },
        "name": "Path"
    }],
    "uri": "lb://finance-order"
},
{
    "filters": [{
         "args": {
            "parts": "0"
        },
        "name": "StripPrefix"
    }],
    "id": "user_route",
    "order": 0,
    "predicates": [{
        "args": {
            "pattern": "/user/**"
        },
        "name": "Path"
    }],
    "uri": "lb://finance-usercenter"
}]

说明:动态路由的目的,在不重启和修改getaway配置文件的情况下,在nacos的配置中心可自由增减路由,即可实现路由访问。

-----------------------------------------整合swagger--------------------------------------------

2.1.swagger的配置文件

依赖
       <!-- Swagger 接口文档 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
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.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.*;

import java.util.Optional;

@RestController
public class SwaggerHandler {
    @Autowired(required = false)//如果有就注入,没有就跳过
    private SecurityConfiguration securityConfiguration;
    @Autowired(required = false)
    private UiConfiguration uiConfiguration;
    private final SwaggerResourcesProvider swaggerResources;

    @Autowired
    public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
        this.swaggerResources = swaggerResources;
    }


    @GetMapping("/swagger-resources/configuration/security")
    public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    @GetMapping("/swagger-resources/configuration/ui")
    public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
    }

    @GetMapping("/swagger-resources")
    public Mono<ResponseEntity> swaggerResources() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }

    @GetMapping("/")
    public Mono<ResponseEntity> swaggerResourcesN() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }

    @GetMapping("/csrf")
    public Mono<ResponseEntity> swaggerResourcesCsrf() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }
}

import lombok.AllArgsConstructor;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.ArrayList;
import java.util.List;

@Component
@Primary
@AllArgsConstructor
public class MySwaggerResourceProvider implements SwaggerResourcesProvider {
    public static final String API_URI = "/v2/api-docs";
    private final RouteLocator routeLocator;
    private final GatewayProperties gatewayProperties;

    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        //取出gateway的route
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        //结合配置的route-路径(Path),和route过滤,只获取有效的route节点
        gatewayProperties.getRoutes().stream()
                .filter(routeDefinition -> routes.contains(routeDefinition.getId()))
                .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
                .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                .forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.getId(),
                                predicateDefinition.getArgs()
                .get(NameUtils.GENERATED_NAME_PREFIX + "0")
                .replace("/**", API_URI)))));
        return resources;
    }

    private SwaggerResource swaggerResource(String name, String location) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        return swaggerResource;
    }
}

2.2.application.yml文件配置

spring:
  application:
    name: finance-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      #路由规则:如果不使用swagger可不用配置
      #要使用swagger必须配置,
      #通过Path=/finance-order/来区分不同的微服务中的swagger
      routes:
        - id: order微服务
          uri: lb://finance-order
          predicates:
            - Path=/finance-order/**
          filters:
            - StripPrefix=1

        - id: user微服务
          uri: lb://finance-usercenter
          predicates:
            - Path=/finance-usercenter/**
          filters:
            - StripPrefix=1

        - id: product微服务
          uri: lb://finance-product
          predicates:
            - Path=/finance-product/**
          filters:
            - StripPrefix=1

        - id: pay微服务
          uri: lb://finance-pay
          predicates:
            - Path=/finance-pay/**
          filters:
            - StripPrefix=1

        - id: promotion微服务
          uri: lb://finance-promotion
          predicates:
            - Path=/finance-promotion/**
          filters:
            - StripPrefix=1


2.3.每一个微服务要配置自己的swagger(依赖是一样的)


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean("xxx模块")
    public Docket createApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(myApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("你的controller路径"))
                .paths(PathSelectors.any())
                .build();

    }

    private ApiInfo myApiInfo() {
        return new ApiInfoBuilder()
                .title("xxx项目-xxx微服务接口文档")
                .description("提供xxx模块的文档")
                .termsOfServiceUrl("http://www.xxx.com/")
                .version("1.0")
                .build();
    }

}

2.3.1.swagger的使用

controller

@RestController
@Api(description = "对外暴露接口")
@Slf4j
public class OrderController {
    
    @PostMapping("xxxx")
    @ApiOperation(value = "这是xxxx方法")
    //对象不需要配置
    public Object xxx(@RequestBody 对象 fo){
        return "ok";
    }

    @ApiOperation("xxxx方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId",value = "xxx",required = true),
            @ApiImplicitParam(name = "currentId",value = "xxx",required = true),
            @ApiImplicitParam(name = "payPassword",value = "xxx",required = true)
    })
    @GetMapping("xxx")
    public Object xxx(String userId,Long currentId,String payPassword){
        return "ok";
    }
}

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("xxx")
public class xxx{
    @ApiModelProperty("xxx")
    private Long xxx;
    @ApiModelProperty("xxx")
    private String xxx;
}

说明:getaway整合swagger,用于把多个微服务的swagger整合到一起,方便查看,以及在getaway中配置过滤器时,验证可不可行。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值