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

相关内容

热门资讯

婚礼现场新郎致辞 婚礼现场新郎致辞各位亲朋好友:  大家好!  人生能有几次最难忘、最幸福的时刻,今天我才真正从内心里...
班会主持稿 班会主持稿(15篇)  在生活中,我们越来越需要主持稿,主持稿是主持人于节目进行过程中串联节目的稿件...
幼儿园开学典礼的主持词 幼儿园开学典礼的主持词范文(精选6篇)  根据活动对象的不同,需要设置不同的主持词。在当下这个社会中...
教师节晚会活动主持词 教师节晚会活动主持词(精选10篇)  主持词是主持人在台上表演的灵魂之所在。在当下的中国社会,很多场...
同学聚会的主持词 同学聚会的主持词3篇  中学时代,是一个人一生中最美好的时光。小编为大家整理了同学聚会的主持词3篇,...
大学毕业典礼主持词 关于大学毕业典礼主持词(通用10篇)  主持词要注意活动对象,针对活动对象写相应的主持词。在当下的中...
宝宝宴主持词 宝宝宴主持词范本  宴会前:尊敬的各位来宾,亲爱的朋友们,我们的宴会将于五分钟之后准时开始,请您抓紧...
周年音乐朗诵会主持词 周年音乐朗诵会主持词  主持词每一项大型活动都不可或缺的一部分重要组成。一项活动的成功与否很大程度上...
甄选春的主持词 甄选春的主持词  活动对象的不同,主持词的写作风格也会大不一样。在如今这个时代,越来越多的场合都需要...
婚礼主婚人致辞 婚礼主婚人致辞(15篇)  在学习、工作、生活中,许多人都有过写致辞的经历,对致辞都不陌生吧,致辞要...
晚会主持人主持稿 晚会主持人主持稿  在我们平凡的日常里,我们需要用到主持稿的情形越来越多,主持稿是主持人在会议或是节...
母亲的生日祝寿词 母亲的生日祝寿词春天像一个风华正茂的少女,迈着轻盈的脚步,如期而至。在这如花似玉的`季节里,今天,我...
幼儿园元旦文艺汇演流程主持词 幼儿园元旦文艺汇演流程主持词  A:谁将平地万秋叶,剪刻做此连天花?  C:秋爽天地显繁华,某园爱意...
主持稿开场白 主持稿开场白  一、什么是主持词  主持词,又叫串连词,串联词,串词。主持词是在晚会、联欢会等大型联...
《熊出没》中的经典台词 《熊出没》中的经典台词  在学习、工作生活中,用到台词的地方越来越多,台词是剧作者用以展示剧情,刻画...
军训开幕式致辞 军训开幕式致辞  在平平淡淡的学习、工作、生活中,大家对致辞都再熟悉不过了吧,致辞受场合、事件的限制...
学校拜师仪式主持词 学校拜师仪式主持词  导读:由主持人于节目进行过程中串联节目的串联词。如今的各种演出活动和集会中,主...
婚礼主持人致辞 婚礼主持人致辞(精选6篇)  在我们平凡的日常里,大家或多或少都用到过致辞吧,致辞具有针对性,要认清...
校园活动主持词 校园活动主持词  【导语】不论是会议还是晚会等活动都需要主持人和主持词,好的主持稿对会议的气氛会起到...
公司酒会主持词 公司酒会主持词  根据活动对象的不同,需要设置不同的主持词。在一步步向前发展的社会中,主持成为很多活...