欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring cloud gateway聚合swagger2

程序员文章站 2022-06-13 14:01:12
...

项目spring cloud基于 Greenwich.SR2, spring boot基于2.1.6.RELEASE
使用swagger可以生成api文档,让我们不再编写api文档,而且还自带调试功能,当然需要自己添加注解丰富文档的内容,单体服务使用swagger相信对大家来说都是没有问题的,下面将简单介绍单体服务使用swagger,以及使用gateway聚合swagger,由于swagger-ui的界面并不是那么还看,所以ui界面使用swagger-bootstrap-ui,一款界面优美的swagger-ui,现在使用了前后端分离,改名叫:knife4j
文档:https://doc.xiaominfo.com/guide/useful.html
新版本我感觉文档还有待完善,感兴趣的可以去看看

单个服务使用swagger
加配置:

		<dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.5</version>
        </dependency> 

添加配置文件,名字随便取:

@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUI
public class SwaggerConfig {

   @Bean
   public Docket docket() {
       return new Docket(DocumentationType.SWAGGER_2)
               .apiInfo(apiInfo())
               .select()
               .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
               .paths(PathSelectors.any())
               .build();
   }

   private ApiInfo apiInfo() {
       return new ApiInfoBuilder()
               .title("TEST-PROVIDER1")
               .description("服务提供者一")
               .version("1.0")
               .contact(new Contact("xx", "", "aaa@qq.com"))
               .build();
   }
}

放行:

@Slf4j
@Configuration
public class WebAppConfig extends WebMvcConfigurationSupport {


    @Autowired
    private GlobalRequestHandler globalRequestHandler;


    /**
     * 处理开启全局异常拦截之后的问题
     * @param registry
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
        registry.addResourceHandler("/doc.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        
        super.addResourceHandlers(registry);
    }

    /**
     * 注册拦截器
     * @param registry
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(this.globalRequestHandler)  //注册改拦截器
                .addPathPatterns("/**")     //表示拦截所有的请求,
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");  //排除 swagger 拦截
    }
}

@EnableSwagger2:开启swagger2
@EnableSwaggerBootstrapUI:开启swagger-bootstrap-ui的增强文档,视情况而定,需要就添加不需要就不添加
其他没啥,网上对于这些的解释一大堆,值得注意的一点是扫描包哪里配置的是Api.class,会扫描所有带有api注解的controller,试想当你的扫描包不再一个目录是怎么办,之前在网上找的方法,但那个代码有个方法过时了,然后就自己和同事研究,个人觉得这个挺好的。
然后访问 ip:端口/doc.html就ok

gateway
我们开发不可能就只有一个服务,所以需要聚合所有的服务的文档
同理加配置:

		<dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.5</version>
        </dependency>

添加配置,因为gate是基于webflux,swagger的资源接口应该是基于web的,所以我们需要自己配置资源接口

@RestController
@RequestMapping("/swagger-resources")
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("/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)));
    }
}

对每个接口不了解的直接布起来后在使用接口访问便知
然后我们需要修改他的路由,取到所有的服务api文档,大概思路是去注册中心取到所有的服务,然后添上文档通用的后缀/v2/api-docs获取文档

@Component
@Primary
public class SwaggerProvider implements SwaggerResourcesProvider {

    /**
     * swagger的api json文档路径
     */
    public static final String API_URI = "/v2/api-docs";
    /**
     * Eureka发现功能的方法的名字,注册的服务会加入这个前缀
     */
    public static final String EUREKA_SUB_PFIX = "CompositeDiscoveryClient_";
    /**
     * 服务发现的路由处理器
     */
    private final DiscoveryClientRouteDefinitionLocator routeLocator;

    public SwaggerProvider(DiscoveryClientRouteDefinitionLocator routeLocator) {
        this.routeLocator = routeLocator;
    }

    @Override
    public List<SwaggerResource> get() {

        List<SwaggerResource> resources = new ArrayList<>();

        List<String> routes = new ArrayList<>();
        //从DiscoveryClientRouteDefinitionLocator 中取出routes,构造成swaggerResource
        routeLocator.getRouteDefinitions().subscribe(routeDefinition -> {
            resources.add(swaggerResource(
                    //获取id(服务注册的id)
                    routeDefinition.getId()
                            //去除CompositeDiscoveryClient_前缀
                            .substring(EUREKA_SUB_PFIX.length()),
                    //获取路由定义信息列表
                    routeDefinition.getPredicates()
                            //获取路径信息PredicateDefinition{name='Path', args={pattern=/byb-provider2/**}}
                            .get(0)
                            .getArgs()
                            //将pattern中的/**替换为服务swagger文档路径
                            .get("pattern")
                            .replace("/**", API_URI)));
        });
        //for是我自己写的过滤没有api文档的代码,自己视情况添加
        for (SwaggerResource swaggerResource : resources) {
            //获取所有服务的文档uri
            String uri = swaggerResource.getUrl();
            //获取服务名
            String serverName = uri.replace(API_URI, "");
            //拼接url
            String url = "http://regist.byb.com:38001/eureka/apps"+serverName;
            //获取RestTemplate实例
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders httpHeaders = new HttpHeaders();
            //添加请求头
            httpHeaders.add("Content-Type", "application/json");
            httpHeaders.add("Accept", "application/json");
            //请求体
            HttpEntity<String> httpEntity = new HttpEntity<String>(null,httpHeaders);
            //发送请求获取响应
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
            String response = responseEntity.getBody();
            //解析json
            JSONObject jsonObject;
            jsonObject = JSONObject.parseObject(response);
            String str1 = jsonObject.getString("application");

            jsonObject = JSONObject.parseObject(str1);
            String str2 = jsonObject.getString("instance");

            JSONArray jsonArray = JSONObject.parseArray(str2);
            String str3 = jsonArray.getString(0);

            jsonObject = JSONObject.parseObject(str3);
            String serverUrl = jsonObject.getString("homePageUrl");
            if (null != serverUrl && !"".equals(serverUrl)) {
                //拼接服务api文档的url
                String serverApi = serverUrl + "v2/api-docs";
                //发送请求
                try {
                    URL url1 = new URL(serverApi);
                    HttpURLConnection  httpUrlConn = (HttpURLConnection) url1.openConnection();
                    //设置连接超时时间
                    httpUrlConn.setConnectTimeout(1000);
                    //获取返回码
                    int code = httpUrlConn.getResponseCode();
                    if (code != 200) {
                        resources.remove(swaggerResource);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }


            }
        }
        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;
    }
}

具体信息注释已经写的很完善了,同理访问ip:端口/doc.html即可访问,左上角即可切换项目,for循环是我自己添加的,用于排除没有api文档的微服务,不需要直接删除即可。
spring cloud gateway聚合swagger2
有问题下方沟通,我应该没有写漏东西。。。
附上swagger的详细注解 –

https://blog.csdn.net/zlhmeng/article/details/100524382