Knife4j+gateway动态路由聚合微服务API
概述knife4j的聚合API,其实官网有现成的例子,但包括其他能搜索到的资料都是基于静态网关的配置,我们现有的都是结合nacos实现动态网关配置,基于此留下这篇完整的教程文档说明:本文假定你有一定的springcloud等相关知识,如没有请自行查找其他资料基础环境spring-boot-dependencies2.2.9.RELEASEspring-cloud-dependenciesHoxto
·
概述
knife4j的聚合API,其实官网有现成的例子,但包括其他能搜索到的资料都是基于静态网关的配置,我们现有的都是结合nacos实现动态网关配置,基于此留下这篇完整的教程文档
说明:本文假定你有一定的springcloud等相关知识,如没有请自行查找其他资料
基础环境
spring-boot-dependencies
2.2.9.RELEASE
spring-cloud-dependencies
Hoxton.SR7
spring-cloud-alibaba-dependencies
2.2.3.RELEASE
knife4j
2.0.9
代码
父parent
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- knife4j提供的微服务starter -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-micro-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
</dependencyManagement>
springcloud 网关
pom
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- knife4j提供的微服务starter -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
</dependencies>
相关配置
- 动态路由配置,一般配置在nacos上,选择json格式
[
{
"id": "xxx",
"order": 1,
"predicates": [
{
"args": {
"pattern": "/api/author/**"
},
"name": "Path"
}
],
"uri": "lb://author-service"
}
]
- 网关配置,建议放在application.yml里面
spring:
cloud:
gateway:
httpclient:
# 全局的TCP连接超时时间默认时间是45秒,网络故障的时候,连接时间要等待45秒,而网络连接是同步阻塞
connect-timeout: 2000
# 全局的响应超时时间,网络链接后,后端服务多久不返回网关就报错 The response timeout.
response-timeout: PT30S
pool:
# scg的空闲连接超时回收时间
max-idle-time: PT1S
websocket:
# 1024*1024*10 上传的文件大小
max-frame-payload-length: 10485760
# 全局跨域配置
#globalcors:
#cors-configurations:
#'[/**]': #匹配所有请求
#allowedOrigins: "*" #跨域处理 允许所有的域
#allowedMethods: # 支持的方法
#- GET
#- POST
#- PUT
#- DELETE
# nacos 服务发现
discovery:
locator:
lowerCaseServiceId: true
enabled: true
# 配置全局路由
#default-filters:
# 开发环境重写路由规则 该配置会影响到灰度组件,如果开启需要关闭灰度组件
#- DevLocalRewriteRouteFilter=true
# 签名校验
#- SecretGatewayFilter=true
动态路由代码实现
DynamicRouteService
动态路由管理服务
import org.springframework.cloud.gateway.route.RouteDefinition;
/**
* TODO NacosDynamicRutesService <br>
*
* @date: 2020/12/7 <br>
* @author: xiaolinlin <br>
* @since: 1.0 <br>
* @version: 1.0 <br>
*/
public interface DynamicRouteService {
/**
* 新增一个route定义
*
* @param routeDefinition : 路由信息
* @param manual: 控制台-手动
* @return java.lang.String
* @author xiaolinlin
* @date 2020/12/7
**/
String addRoute(RouteDefinition routeDefinition,boolean manual);
/**
* 更新一个route定义
*
* @param routeDefinition :
* @return java.lang.String
* @author xiaolinlin
* @date 2020/12/7
**/
String updateRoute(RouteDefinition routeDefinition);
/**
* 通过ID删除一个route定义
*
* @param id :
* @return java.lang.String
* @author xiaolinlin
* @date 2020/12/7
**/
String deleteRoute(String id);
AbstractDynamicRouteService
基类实现
import com.alibaba.fastjson.JSONObject;
import java.util.ArrayList;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.http.ResponseEntity;
import reactor.core.publisher.Mono;
/**
* 动态路由配置抽象类<br>
*
* @date: 2020/12/23 <br>
* @author: xiaolinlin <br>
* @since: 1.0 <br>
* @version: 1.0 <br>
*/
@Slf4j
public abstract class AbstractDynamicRouteService implements DynamicRouteService, ApplicationEventPublisherAware,
DisposableBean {
@Autowired
protected RouteDefinitionWriter routeDefinitionWriter;
protected ApplicationEventPublisher applicationEventPublisher;
/**
* 路由列表 TODO 分布式配置
*/
protected static final List<String> ROUTE_LIST = new ArrayList<>();
/**
* 新增一个route定义
*
* @param routeDefinition :
* @param manual: 是否手动配置
* @return java.lang.String
* @author xiaolinlin
* @date 2020/12/7
**/
@Override
public String addRoute(RouteDefinition routeDefinition, boolean manual) {
try {
log.debug("新增route配置:{}", JSONObject.toJSONString(routeDefinition));
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
ROUTE_LIST.add(routeDefinition.getId());
if (manual) {
// 手动发布,每添加一次更新一次
publish();
}
} catch (Exception e) {
log.error("添加路由失败,当前路由信息:{},错误详情:{}", JSONObject.toJSONString(routeDefinition), e);
}
return "success";
}
/**
* 更新一个route定义
*
* @param routeDefinition :
* @return java.lang.String
* @author xiaolinlin
* @date 2020/12/7
**/
@Override
public String updateRoute(RouteDefinition routeDefinition) {
if (null == routeDefinition) {
return "fail";
}
log.debug("更新route配置:{}", JSONObject.toJSONString(routeDefinition));
String id = routeDefinition.getId();
try {
this.routeDefinitionWriter.delete(Mono.just(id));
this.routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
publish();
} catch (Exception e) {
log.error("更新路由信息失败,当前ID:{},错误信息:{}", id, e);
return "fail";
}
return "success";
}
/**
* 通过ID删除一个route定义
*
* @param id :
* @return java.lang.String
* @author xiaolinlin
* @date 2020/12/7
**/
@Override
public String deleteRoute(String id) {
if (StringUtils.isEmpty(id)) {
return "fail";
}
log.debug("触发了删除route配置,路由ID: {}", id);
try {
this.routeDefinitionWriter.delete(Mono.just(id))
.then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build())))
.onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build()))
.subscribe();
return "success";
} catch (Exception e) {
log.error("删除路由失败,当前路由ID:{},异常原因:{}", id, e);
return "fail";
}
}
/**
* 初始化路由配置
*
* @param config :
* @return void
* @author xiaolinlin
* @date 2020/12/7
**/
protected void initConfig(String config) {
if (StringUtils.isEmpty(config)) {
return;
}
List<RouteDefinition> gatewayRouteDefinitions = JSONObject
.parseArray(config, RouteDefinition.class);
for (RouteDefinition routeDefinition : gatewayRouteDefinitions) {
addRoute(routeDefinition, false);
}
// 重新发布更新
publish();
}
/**
* 发布重新更新
*
* @return void
* @author xiaolinlin
* @date 2020/12/7
**/
protected void publish() {
log.info("当前网关路径节点:{}", JSONObject.toJSONString(ROUTE_LIST));
this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
}
/**
* clearRoute
*
* @author xiaolinlin
* @date 2020/12/7
**/
protected void clearRoute() {
for (String id : ROUTE_LIST) {
this.deleteRoute(id);
}
ROUTE_LIST.clear();
}
/**
* Set the ApplicationEventPublisher that this object runs in.
* <p>Invoked after population of normal bean properties but before an init
* callback like InitializingBean's afterPropertiesSet or a custom init-method. Invoked before ApplicationContextAware's
* setApplicationContext.
*
* @param applicationEventPublisher event publisher to be used by this object
*/
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
@Override
public void destroy() throws Exception {
ROUTE_LIST.clear();
}
}
- nacos实现
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import xxx.AbstractDynamicRouteService;
import java.util.Properties;
import java.util.concurrent.Executor;
import javax.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
/**
* 动态网关调整<br>
*
* @date: 2020/12/7 <br>
* @author: xiaolinlin <br>
* @since: 1.0 <br>
* @version: 1.0 <br>
*/
@Service
@RefreshScope
@Slf4j
public class NacosDynamicRoutesImpl extends AbstractDynamicRouteService {
// nacos 的配置信息
/// private NacosConfigProperties nacosConfigProperties;
/**
* nacos服务地址
*
*
*
*
*
*/
@Value("${spring.cloud.nacos.server-addr}")
private String serverAddr;
/**
* namespace
*/
@Value("${spring.cloud.nacos.discovery.namespace}")
private String nameSpace;
/**
* 配置组
*/
@Value("${spring.cloud.nacos.config.discovery.group:DEFAULT_GROUP}")
private String gourpId;
/**
* 动态路由dataID,JSON格式, 重点关注这里,nacos上的名称
*/
@Value("${spring.cloud.nacos.config.route-data-id:xiaogj-youli-platform-gateway-route}")
private String routeDataId;
/**
* 初始化启动监听nacos配置
*
* @return void
* @author xiaolinlin
* @date 2020/12/7
**/
@PostConstruct
public void dynamicRouteByNacosListener() {
log.info("gateway route init...");
try {
Properties properties = new Properties();
properties.setProperty("serverAddr", serverAddr);
properties.setProperty("namespace", nameSpace);
ConfigService configService = NacosFactory.createConfigService(properties);
String config = configService.getConfig(routeDataId, gourpId, 5000);
// 初次初始化
initConfig(config);
// 动态更新
configService.addListener(routeDataId, gourpId, new Listener() {
@Override
public Executor getExecutor() {
return null;
}
@Override
public void receiveConfigInfo(String configInfo) {
clearRoute();
try {
log.info("配置发生了变更,变更网关配置内容:{}", configInfo);
initConfig(configInfo);
} catch (Exception e) {
log.warn("本次配置更新失败,错误详情:", e);
}
}
});
} catch (NacosException e) {
log.error("监听网关路由配置异常,错误信息:", e);
}
}
}
swagger 代码部分
SwaggerHandler
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
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.SwaggerResourcesProvider;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
/**
* swagger <br>
*
* @date: 2021/9/22 <br>
* @author: llxiao <br>
* @since: 1.0 <br>
* @version: 1.0 <br>
*/
@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));
}
@SuppressWarnings("rawtypes")
@GetMapping("")
public Mono<ResponseEntity> swaggerResources() {
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
}
SwaggerProvider
主要是用于适配nacos动态路由
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import reactor.core.publisher.Flux;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
/**
* 聚合系统接口<br>
*
* @date: 2021/9/22 <br>
* @author: llxiao <br>
* @since: 1.0 <br>
* @version: 1.0 <br>
*/
@Slf4j
@Component
@Primary
@AllArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer {
/**
* Swagger2默认的url后缀
*/
public static final String SWAGGER2URL = "/v2/api-docs";
/**
* 网关路由
*/
///@Autowired
///private RouteLocator routeLocator;
/**
* yml方式获取路由服务
*/
///@Autowired
///private GatewayProperties gatewayProperties;
/**
* 使用动态路由,获取到指定的路由规则
*/
@Autowired
private RouteDefinitionRepository routeDefinitionRepository;
/**
* 聚合其他服务接口
*
* @return java.util.List<springfox.documentation.swagger.web.SwaggerResource>
* @author llxiao
* @date 2022/3/30
**/
@Override
public List<SwaggerResource> get() {
//接口资源列表
List<SwaggerResource> resourceList = new ArrayList<>();
//服务名称列表
Set<String> routeHosts = new HashSet<>();
// 去重,多负载服务只添加一次
Set<String> existsServer = new HashSet<>();
// 动态网关方式获取路由 nacos动态网关
Flux<RouteDefinition> routeDefinitions = routeDefinitionRepository.getRouteDefinitions();
routeDefinitions.subscribe(routeDefinition -> {
List<PredicateDefinition> predicates = routeDefinition.getPredicates();
if (CollectionUtil.isNotEmpty(predicates)) {
String host = routeDefinition.getUri().getHost();
routeHosts.add(host);
String url = "/" + host + SWAGGER2URL;
if (!existsServer.contains(url)) {
existsServer.add(url);
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setUrl(url);
swaggerResource.setName(host);
resourceList.add(swaggerResource);
}
}
});
log.info("网关服务地址列表:{}", JSON.toJSONString(routeHosts));
return resourceList;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/** swagger-ui 地址 */
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
//favicon.ico
registry.addResourceHandler("/favicon.ico")
.addResourceLocations("classpath:/static/");
}
}
SwaggerHeaderFilter
可选,按需添加
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
/**
* SwaggerHeaderFilter <br>
*
* @date: 2022/3/31 <br>
* @author: llxiao <br>
* @since: 1.0 <br>
* @version: 1.0 <br>
*/
@SuppressWarnings("ALL")
@Configuration
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
private static final String URI = "/v2/api-docs";
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if (StringUtils.endsWithIgnoreCase(path, URI)) {
String basePath = path.substring(0, path.lastIndexOf(URI));
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
} else {
return chain.filter(exchange);
}
};
}
}
微服务Knife4j引用公共组件
- pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
</dependencies>
- 代码部分
2.1.Knife4jConfig
相关配置
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* Knife4jConfig <br>
*
* @date: 2021/11/26 <br>
* @author: llxiao <br>
* @since: 1.0 <br>
* @version: 1.0 <br>
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "knife.swagger")
public class Knife4jConfig {
private String version;
private String basePackage;
private String title;
private String description;
private String contactName;
private Boolean enabled;
private String termsOfServiceUrl = "https://xxx.com";
}
2.2. Knife4jConfiguration
核心实现
import java.util.ArrayList;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMethod;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.service.ResponseMessage;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
/**
* Knife4jConfiguration <br>
*
* @date: 2021/11/26 <br>
* @author: llxiao <br>
* @since: 1.0 <br>
* @version: 1.0 <br>
*/
@Configuration
@ComponentScan(basePackages = "com.xx.swagger")
@EnableSwagger2WebMvc
@Slf4j
public class Knife4jConfiguration {
@Bean(value = "defaultApi2")
public Docket defaultApi2(Knife4jConfig knife4jConfig) {
// 自定义统一错误码返回 -需要自行修改,仅供参考
List<ResponseMessage> responseMessageList = new ArrayList<>();
for (XXXCommonExceptionCode value : XXXCommonExceptionCode.values()) {
ResponseMessage build = new ResponseMessageBuilder().code(value.getCode()).message(value.getMsg()).responseModel(
new ModelRef(value.getMsg())).build();
responseMessageList.add(build);
}
// 自定义通用header 定义 -需要自行修改,仅供参考
List<Parameter> parameters = new ArrayList<>();
parameters.add(new ParameterBuilder()
.name("Auth-Token")
.description("我是描述")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false)
.build());
log.info("Knife4j 加载完成....");
return new Docket(DocumentationType.SWAGGER_2)
// 自定义错误码
.globalResponseMessage(RequestMethod.GET, responseMessageList)
.globalResponseMessage(RequestMethod.POST, responseMessageList)
.globalResponseMessage(RequestMethod.PUT, responseMessageList)
.globalResponseMessage(RequestMethod.DELETE, responseMessageList)
// header参数定义
.globalOperationParameters(parameters)
.apiInfo(new ApiInfoBuilder()
.title(knife4jConfig.getTitle())
.description(knife4jConfig.getDescription())
.termsOfServiceUrl(knife4jConfig.getTermsOfServiceUrl())
.contact(new Contact(knife4jConfig.getContactName(), "", ""))
.version(knife4jConfig.getVersion())
.build())
//分组名称
// .groupName(knife4jConfig.getVersion())
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage(knife4jConfig.getBasePackage()))
.paths(PathSelectors.any())
.build();
}
}
2.2.3 EnabledKnife4j
使用注解开启
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* EnabledCustomSwagger2 <br>
*
* @date: 2022/3/30 <br>
* @author: llxiao <br>
* @since: 1.0 <br>
* @version: 1.0 <br>
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Knife4jConfiguration.class})
public @interface EnabledKnife4j {
}
2.2.4 配置参考
knife:
swagger:
version: 1.0
basePackage: com.xx.controller
title: 标题
description: 描述
contactName: 联系人
enabled: true
2.2.5 微服务端引入上述代码和配置,并在主启动类中添加@EnabledKnife4j
注解即可
打开使用
http://gateway网关地址/doc.htm
更多推荐
已为社区贡献3条内容
所有评论(0)