springcloud-gateway集成knife4j
创始人
2024-06-02 08:03:50
0

springcloud-gateway集成knife4j

  • springcloud-gateway集成knife4j
    • 环境信息
    • 准备工作
    • 微服务集成knife4j
      • 第一步:编写Knife4jApiInfoProperties
      • 第二步:编写配置类Knife4jConfig
      • 第三步:放行相关静态资源
    • 网关集成knife4j
      • 编写配置类Knife4jGatewayConfig
    • 测试验证
    • 相关资料

环境信息

  • spring-boot:2.6.3
  • spring-cloud-alibaba:2021.0.1.0
  • knife4j-openapi2-spring-boot-starter:4.0.0

准备工作

各微服务&网关引入依赖

com.github.xiaoyminknife4j-openapi2-spring-boot-starter4.0.0

微服务集成knife4j

第一步:编写Knife4jApiInfoProperties

import com.ideaaedi.springcloud.jd.commonspring.config.Knife4jConfig;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;/*** api 基础信息配置。更多配置信息项见{@link Knife4jConfig}** @author JustryDeng * @since 2021.0.1.D*/
@Data
@Component
public class Knife4jApiInfoProperties {/*** 要扫描api的base包*/@Value("${api-info.base-package:com}")private String basePackage;/*** 是否启用登录认证*/@Value("${api-info.enable-security:true}")private boolean enableSecurity;/*** 文档标题*/@Value("${api-info.title:}")private String title;/*** 文档描述*/@Value("${api-info.description:api info}")private String description;/*** 文档版本*/@Value("${api-info.version:1.0.0}")private String version;/*** 联系人姓名*/@Value("${api-info.contact-name:JustryDeng}")private String contactName;/*** 联系人网址*/@Value("${api-info.contact-url:https://gitee.com/JustryDeng/projects}")private String contactUrl;/*** 联系人邮箱*/@Value("${api-info.contact-email:13548417409@163.com}")private String contactEmail;
}

第二步:编写配置类Knife4jConfig

import com.ideaaedi.springcloud.jd.commonds.constant.BaseConstant;
import com.ideaaedi.springcloud.jd.commonspring.config.properties.Knife4jApiInfoProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;import java.util.ArrayList;
import java.util.List;/*** knife4j配置类** @author JustryDeng * @since 2021.0.1.D*/
@Slf4j
@Configuration
public class Knife4jConfig implements WebMvcConfigurer {/** 文档相关资源的链接(需保证这些资源不需要鉴权即可访问) */public static String[] RESOURCE_URLS = new String[]{"/webjars/**", "/swagger**", "/v2/api-docs", "/doc.html"};@Value("${spring.application.name:}")private String applicationName;@Beanpublic Docket docket(Knife4jApiInfoProperties knife4jApiInfoProperties) {String apiBasePackage = knife4jApiInfoProperties.getBasePackage();Docket docket = new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo(knife4jApiInfoProperties)).select().apis(RequestHandlerSelectors.basePackage(apiBasePackage)).paths(PathSelectors.any()).build();if (knife4jApiInfoProperties.isEnableSecurity()) {docket.securitySchemes(securitySchemes()).securityContexts(securityContexts());}return docket;}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}private ApiInfo apiInfo(Knife4jApiInfoProperties knife4jApiInfoProperties) {return new ApiInfoBuilder().title(knife4jApiInfoProperties.getTitle()).description(knife4jApiInfoProperties.getDescription()).termsOfServiceUrl(StringUtils.isBlank(applicationName) ? "" : "/" + applicationName).contact(new Contact(knife4jApiInfoProperties.getContactName(), knife4jApiInfoProperties.getContactUrl(), knife4jApiInfoProperties.getContactEmail())).version(knife4jApiInfoProperties.getVersion()).build();}private List securitySchemes() {// 设置请求头信息List result = new ArrayList<>();// 第一个参数,自定义即可。 如:BaseConstant.JWT_TOKEN_KEY=Auth-Token,然后在代码里request.getHeader(BaseConstant.JWT_TOKEN_KEY)取值ApiKey apiKey = new ApiKey(BaseConstant.JWT_TOKEN_KEY, "Authorization", "header");result.add(apiKey);return result;}private List securityContexts() {// 设置需要登录认证的路径List result = new ArrayList<>();result.add(getContextByPath("/*/.*"));return result;}private SecurityContext getContextByPath(String pathRegex) {return SecurityContext.builder().securityReferences(defaultAuth()).forPaths(PathSelectors.regex(pathRegex)).build();}private List defaultAuth() {List result = new ArrayList<>();AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];authorizationScopes[0] = authorizationScope;result.add(new SecurityReference("Authorization", authorizationScopes));return result;}}

第三步:放行相关静态资源

对于管控了权限的应用,应放行以下资源

# 需要放行的资源已经定义进上面编写的Knife4jConfig中
public static String[] RESOURCE_URLS = new String[]{"/webjars/**", "/swagger**", "/v2/api-docs", "/doc.html"};

网关集成knife4j

编写配置类Knife4jGatewayConfig

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;/*** 网关knife4j配置** @author JustryDeng * @since 2021.0.1.D*/
@RestController
public class Knife4jGatewayConfig {private final SecurityConfiguration securityConfiguration;private final UiConfiguration uiConfiguration;private final SwaggerResourceAdapter swaggerResourceAdapter;public Knife4jGatewayConfig(@Autowired(required = false) SecurityConfiguration securityConfiguration,@Autowired(required = false) UiConfiguration uiConfiguration,SwaggerResourceAdapter swaggerResourceAdapter) {this.securityConfiguration = securityConfiguration;this.uiConfiguration = uiConfiguration;this.swaggerResourceAdapter = swaggerResourceAdapter;}/*** 安全配置*/@GetMapping("/swagger-resources/configuration/security")public Mono> securityConfiguration() {return Mono.just(new ResponseEntity<>(Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));}/*** ui配置*/@GetMapping("/swagger-resources/configuration/ui")public Mono> uiConfiguration() {return Mono.just(new ResponseEntity<>(Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));}/*** 资源配置,自动路由到微服务中的各个服务的api-docs信息*/@GetMapping("/swagger-resources")public Mono>> swaggerResources() {return Mono.just(new ResponseEntity<>(swaggerResourceAdapter.get(), HttpStatus.OK));}/*** favicon.ico*/@GetMapping("/favicon.ico")public Mono> favicon() {return Mono.just(new ResponseEntity<>(null, HttpStatus.OK));}/*** swagger资源适配器** @author JustryDeng * @since 2021.0.1.D*/@Slf4j@Componentpublic static class SwaggerResourceAdapter implements SwaggerResourcesProvider {/*** spring-cloud-gateway是否开启了根据服务发现自动为服务创建router*/@Value("${spring.cloud.gateway.discovery.locator.enabled:false}")private boolean autoCreateRouter;@Value("${spring.application.name:}")private String applicationName;@Resourceprivate RouteLocator routeLocator;@Resourceprivate GatewayProperties gatewayProperties;/*** 根据当前所有的微服务路由信息,创建对应的SwaggerResource*/@Overridepublic List get() {List finalResources;Set routes = new LinkedHashSet<>(16);// 获取所有路由的idrouteLocator.getRoutes().subscribe(route -> {String routeId = route.getId();routeId = routeId.replace("ReactiveCompositeDiscoveryClient_", "");routes.add(routeId);});// 没有开启自动创建路由,那么走配置文件中配置的路由if (!autoCreateRouter) {finalResources = new ArrayList<>(16);gatewayProperties.getRoutes().stream()// 过滤出配置文件中定义的路由.filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route -> {route.getPredicates().stream()// 过滤出设置有Path Predicate的路由.filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))// 根据路径拼接成api-docs路径,生成SwaggerResource.forEach(predicateDefinition -> finalResources.add(swaggerResource(route.getId(),predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("**", "v2/api-docs"))));});} else {finalResources = routes.stream().map(routeId -> swaggerResource(routeId, routeId + "/v2/api-docs")).collect(Collectors.toList());}List resources = new ArrayList<>(finalResources);// resources过滤掉网关的SwaggerResource, 我们一般也不会在网关中编写业务controllerif (StringUtils.isNotBlank(applicationName)) {resources = resources.stream().filter(x -> !applicationName.equalsIgnoreCase(x.getName())).collect(Collectors.toList());}// 排序resources.sort(Comparator.comparing(x -> x.getName().length()));return resources;}/*** 创建swagger资源** @param name*            swagger资源名(注:一般对应 {路由id})* @param location*            swagger资源路径(注:一般对应 {路由id}/v2/api-docs)* @return  swager资源*/private SwaggerResource swaggerResource(String name, String location) {log.info("name:{},location:{}", name, location);SwaggerResource swaggerResource = new SwaggerResource();swaggerResource.setName(name);swaggerResource.setLocation(location);swaggerResource.setSwaggerVersion("2.0");return swaggerResource;}}
}

测试验证

启动微服务后,访问{网关}/doc.html完成验证

在这里插入图片描述

相关资料

  • springboot2集成knife4j
  • 在微服务项目中引入 knife4j
  • 本文已被收录进《程序员成长笔记》 ,笔者JustryDeng

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...