spring cloud gateWay集成knife4j实现文档聚合

背景
gateWay 介绍

gateway相当于所有服务的门户,将客户端请求与服务端应用相分离,客户端请求通过gateway后由定义的路由和断言进行转发,路由代表需要转发请求的地址,断言相当于请求这些地址时所满足的条件,只有同时符合路由和断言才给予转发。

knife4j

knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名kni4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍!

集成原因

在前后端的分离架构中,为了节约前后端的交流成本,会在每个单体架构中引入knife4j生成接口的在线文档,但是采用gateWay之后,对于前端来说,后端就只有一个统一的入口去访问,所以需要将gateWay和knife4j结合,实现各微服务的文档聚合。

步骤
创建swagger服务模块,用于其他业务模块,去调用。
  1. 引入依赖
 <!--swagger2  增强版接口文档-->
        <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-spring-boot-starter</artifactId>
        <version>2.0.6</version>
    </dependency>
  1. 创建配置类
/**
 * created by dsl on 2022/6/25
 * swagger2配置(这里只是将创建swagger所需要的类注入到容器中)
 */
@Component
public class SwaggerConfig {
    @Bean
    public DocketBuilder docketBuilder() {
        return new DocketBuilder();
    }

    public class DocketBuilder {
        public DocketBuilder() {
        }

        public Docket createBaseDocket(ApiInfo apiInfo, String basePackage,String groupName) {
            return  new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo)
                    .groupName(groupName)
                    // 设置哪些接口暴露给Swagger展示
                    .select()
                    // 扫描所有有注解的api,用这种方式更灵活
                    .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                    // 扫描指定包中的swagger注解
                    .apis(RequestHandlerSelectors.basePackage(basePackage))
                    .paths(PathSelectors.any())
                    .build()
                    .securityContexts(Lists.newArrayList(securityContext(),securityContext1())).securitySchemes(Lists.<SecurityScheme>newArrayList(apiKey(),apiKey1()))
                    .globalOperationParameters(getParameterList());//设置全局请求头
        }

        public ApiInfo buildApiInfo(String title, String description, String version) {
            return (new ApiInfoBuilder()).title(title).description(description).contact(new Contact("hd", "https://swagger.io/", "1711054839@qq.com")).version(version).build();
        }

        private ApiKey apiKey() {
            return new ApiKey("BearerToken", "Authorization", "header");
        }
        private ApiKey apiKey1() {
            return new ApiKey("BearerToken1", "Authorization-x", "header");
        }

        private SecurityContext securityContext() {
            return SecurityContext.builder()
                    .securityReferences(defaultAuth())
                    .forPaths(PathSelectors.regex("/.*"))
                    .build();
        }
        private SecurityContext securityContext1() {
            return SecurityContext.builder()
                    .securityReferences(defaultAuth1())
                    .forPaths(PathSelectors.regex("/.*"))
                    .build();
        }

        List<SecurityReference> defaultAuth() {
            AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
            AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
            authorizationScopes[0] = authorizationScope;
            return Lists.newArrayList(new SecurityReference("BearerToken", authorizationScopes));
        }
        List<SecurityReference> defaultAuth1() {
            AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
            AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
            authorizationScopes[0] = authorizationScope;
            return Lists.newArrayList(new SecurityReference("BearerToken1", authorizationScopes));
        }
        /**
         * 添加header参数配置
         */
        private List<Parameter> getParameterList() {
            ParameterBuilder clientIdTicket = new ParameterBuilder();
            List<Parameter> pars = new ArrayList<Parameter>();
            clientIdTicket.name("token").description("token请求头")
                    .modelRef(new ModelRef("string"))
                    .parameterType("header")
                    .required(true).build(); //设置false,表示clientId参数 非必填,可传可不传!
            pars.add(clientIdTicket.build());
            return pars;
        }
    }
}
业务模块引入swagger服务模块

项目中使用的业务模块有user和test模块,这里以user模块为例,进行介绍。

  1. 引入swagger模块的服务
    <dependency>
        <groupId>cn.hd.swagger-service</groupId>
        <artifactId>swagger-service</artifactId>
        <version>1.0</version>
    </dependency>
  1. 创建配置类
@Configuration
@EnableSwagger2WebMvc
public class ApiGroupConfig {

    @Autowired
    SwaggerConfig swaggerConfig;

    @Bean
    public Docket createRestApi() {
        SwaggerConfig.DocketBuilder docketBuilder = swaggerConfig.docketBuilder();
        ApiInfo apiInfo = docketBuilder.buildApiInfo("userService", "用户服务", "v1.0");
        return docketBuilder.createBaseDocket(apiInfo, "cn.hd.userService","user");
    }
}
网关模块聚合业务模块的swagger文档
  1. 引入swagger模块依赖
<dependency>
  <groupId>cn.hd.swagger-service</groupId>
   <artifactId>swagger-service</artifactId>
   <version>1.0</version>
</dependency>
  1. 重写SwaggerResourcesProvider获取路由资源

注意:swagger配置时,都加了分组,加了分组会导致,swagger-resources的资源无法加载,文档聚合处分组不显示,在这是通过将服务后缀统一命名为Service,设置资源url时,统一拼接group进行解决的。后续寻找更好的办法来解决这个问题。

@Component
@RequiredArgsConstructor
public class MySwaggerResourceProvider implements SwaggerResourcesProvider {

    /**
     * swagger2默认的url后缀
     */
    private static final String SWAGGER2_URL = "/v2/api-docs";

    /**
     * 路由定位器
     */
    private final RouteLocator routeLocator;

    /**
     * 网关应用名称
     */
    @Value("${spring.application.name}")
    private String gatewayName;
    /**
     * 获取 Swagger 资源
     */
    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routeHosts = new ArrayList<>();
        // 1. 获取路由Uri 中的Host=> 服务注册则为服务名=》app-service001
        routeLocator.getRoutes()
                .filter(route -> route.getUri().getHost() != null)
                .filter(route -> !gatewayName.equals(route.getUri().getHost()))
                .subscribe(route -> routeHosts.add(route.getUri().getHost()));
        // 2. 创建自定义资源
        for (String routeHost : routeHosts) {
            String serviceUrl = "/" + routeHost + SWAGGER2_URL; // 后台访问添加服务名前缀
            SwaggerResource swaggerResource = new SwaggerResource(); // 创建Swagger 资源
            String group = routeHost.replace("Service","");
            //如果设置的有分组,则需要将相应的资源信息加上分组
            swaggerResource.setUrl(serviceUrl+"?group="+group.trim()); // 设置访问地址
            swaggerResource.setName(routeHost); // 设置名称
            swaggerResource.setSwaggerVersion("3.0.0");
            resources.add(swaggerResource);
        }
        return resources;
    }
}
  1. 重写swagger-resources的访问接口
@RestController
@RequestMapping("/swagger-resources")
@RequiredArgsConstructor
public class SwaggerResourceController {
    private final MySwaggerResourceProvider swaggerResourceProvider;

    @RequestMapping
    public ResponseEntity<List<SwaggerResource>> swaggerResources() {
        return new ResponseEntity<>(swaggerResourceProvider.get(), HttpStatus.OK);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何一平?

你的收获就是我学习的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值