Swagger文档Knife4J文档Docket分栏分组优化,改为配置文件
Swagger快速调试接口还是很方便的,Knife4J的美化包后的Swagger文档页面更加舒适,但是当接口非常多时,找起来就很不方便,所以有了Docket分栏分组,但是需要手动在Swagger配置Bean里添加各种Docket配置,非常不方便,所以写了个简单的配置功能注解,用于从配置文件中读取实现自动Docket分栏。
先看使用效果:
一、Springboot启动类上添加编写的自定义注解@EnableSwaggerDocket
。
可选参数enableEnv用于控制Swagger文档在哪些环境启用,不传递默认在dev和test环境打开,其他环境文档将不显示。
@SpringBootApplication
@EnableSwaggerDocket(enableEnv = {"dev", "test", "default", "local"})
public class TestSwaggerApplication {
public static void main(String[] args) {
SpringApplication.run(TestSwaggerApplication.class, args);
}
}
二、在启动配置文件如bootstrap.yaml
或application.yaml
中添加以下配置:
swagger:
docket-config:
dockets:
- id: education
groupName: 教育培训责任
basePackage: com.chabits.api.education
- id: safety
groupName: 安全管理责任
basePackage: com.chabits.api.safety
- id: committee
groupName: 专委会责任
basePackage: com.chabits.api.committee
注意id不可重复,否则会被覆盖,groupName即分栏名称,basePackage是接口所在包名,包下面的所有接口都会被添加到该分栏。
三、启动项目,访问文档地址,切换Docket查看效果
下面贴自定义注解@EnableSwaggerDocket
实现代码:
package com.chabits.common.annotations;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import org.springframework.core.type.AnnotationMetadata;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import java.lang.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
/**
* 开启Swagger Docket分栏
*
* @author Q**
* @date 2024/01/03
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(EnableSwaggerDocket.SwaggerDocketRegister.class)
public @interface EnableSwaggerDocket {
/**
* 根据环境控制Swagger文档显示 <br />
* 默认仅在 {@code dev/test} 环境显示文档, 其他环境不显示
* 语法同 {@link Profiles#of(String...)}
*/
String[] enableEnv() default {"dev", "test"};
class SwaggerDocketRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private Environment env;
/**
* 扫描 {@code swagger.docket-config} 配置 动态创建Docket <br />
* 创建默认Docket 默认扫描所有标记了{@link ApiOperation}注解的接口
*
* @see SwaggerDocketAutoConfiguration
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Map<String, Object> attributes = importingClassMetadata.getAnnotationAttributes(EnableSwaggerDocket.class.getName());
if (attributes != null) {
String[] enableEnvs = (String[]) attributes.get("enableEnv");
boolean enable = env.acceptsProfiles(Profiles.of(enableEnvs));
registryDocket(registry, "defaultDocket", "Knife4J 接口文档", "default", RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class), enable);
BindResult<SwaggerDocketAutoConfiguration> bind = Binder.get(env).bind("swagger.docket-config", SwaggerDocketAutoConfiguration.class);
bind.ifBound(docketConfiguration -> {
if (docketConfiguration.dockets != null && docketConfiguration.dockets.size() > 0) {
docketConfiguration.dockets.forEach(docketConfig -> registryDocket(registry, docketConfig, enable));
}
});
}
}
private void registryDocket(BeanDefinitionRegistry registry, SwaggerDocketAutoConfiguration.DocketConfig docketConfig, boolean enable) {
this.registryDocket(registry, docketConfig.getId(), docketConfig.getGroupName(), docketConfig.getGroupName(), RequestHandlerSelectors.basePackage(docketConfig.getBasePackage()), enable);
}
/**
* 注入Docket到清单
*/
private void registryDocket(BeanDefinitionRegistry registry, String id, String title, String groupName, Predicate<RequestHandler> selector, boolean enable) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(GroupByDocket.class)
.addConstructorArgValue(title)
.addConstructorArgValue(groupName)
.addConstructorArgValue(selector)
.addConstructorArgValue(enable);
registry.registerBeanDefinition("SwaggerDocket" + id, builder.getBeanDefinition());
}
@Override
public void setEnvironment(Environment environment) {
this.env = environment;
}
}
@Data
@EnableConfigurationProperties(SwaggerDocketAutoConfiguration.class)
@ConfigurationProperties(prefix = "swagger.docket-config")
class SwaggerDocketAutoConfiguration {
private List<DocketConfig> dockets = new ArrayList<>();
@Data
public static class DocketConfig {
private String id;
private String groupName;
private String basePackage;
}
}
class GroupByDocket extends Docket {
public GroupByDocket(String title, String groupName, Predicate<RequestHandler> selector, boolean enable) {
super(DocumentationType.SWAGGER_2);
super.enable(enable)
.apiInfo(new ApiInfoBuilder()
.title(title)
.description(title + "相关API")
.version("1.0")
.build()
).groupName(groupName)
.select()
.apis(selector)
.paths(PathSelectors.any())
.build();
}
}
}
注:如果希望写配置文件有提示,或者看idea标红烦人,可以引入spring官方的配置处理器,生成配置规约文件。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
maven中引入后清理并重新打包后,就会在写yaml时有提示了:
其实主要是打包后生成了这个东西: