1、在讲如何实现swagger自动配置之前,我先讲一下,我们平常使用swagger的时候通常是怎么配置的,如下面的代码块:
@Bean
@Order(value = 1)
public Docket groupRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.demo.controller"))
.paths(PathSelectors.any())
.build();
}
/**
* 创建Swagger页面 信息
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder ().title("微服务")
.description("微服务")
.version("1.0")
.build();
}
这种方式通常我们项目简单的时候,可以这么配置,一旦项目很大,一个大的工程项目往往由多个模块组成,模块多了对api文档就得分组,不然默认在一个分组里面,就会导致里面的接口很多,不易查看,我们一般可能会通过在java代码中配置多个docket,如果以后又要分组,又得需要修改java代码,在里面增加新的分组,这种方式,往往不具有可扩展性,每次都需要修改代码,重新编译?如何解决这个问题呢?见下面一节具体实现
2、为了实现swagger配置的可扩展的特性,通过spring读取配置文件自动注入docket方式来解决这个问题,具体实现细节如下:
2.1.获取bean的注册中心和spring的上下文,具体代码如下:
@Component
@Getter
public class SimpleBeanDefinitionRegistryProcessor implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
private BeanDefinitionRegistry registry;
private ApplicationContext context;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
this.registry = beanDefinitionRegistry;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}
2.2.swagger读取配置自动生成docket的实现,具体代码如下:
@Configuration
@EnableConfigurationProperties(Swagger2Properties.class)
public class Swagger2AutoConfiguration {
/**
* The Processor.
*/
private final SimpleBeanDefinitionRegistryProcessor processor;
/**
* The Swagger 2 properties.
*/
private final Swagger2Properties swagger2Properties;
/**
* Instantiates a new Swagger 2 auto configuration.
*
* @param processor the processor
* @param swagger2Properties the swagger 2 properties
*/
public Swagger2AutoConfiguration(SimpleBeanDefinitionRegistryProcessor processor, Swagger2Properties swagger2Properties) {
this.processor = processor;
this.swagger2Properties = swagger2Properties;
}
/**
* Inject swagger 2 dockets.
*/
@PostConstruct
public void injectSwagger2Dockets() {
if (Objects.isNull(swagger2Properties)) {
return;
}
List<Map<String, String>> dockets = swagger2Properties.getDocket();
if (CollectionUtils.isEmpty(dockets)) {
return;
}
Map<String, String> docketMap;
for (int var0 = 0; var0 < dockets.size(); var0++) {
String docketName = "swagger2Docket" + var0;
docketMap = dockets.get(var0);
// 注册docket到spring注册中心
processor.getRegistry().registerBeanDefinition(docketName, generateRootBeanDefinition(docketMap));
// 通过spring上下文获取到刚注册到的docket
Docket injectDocket = (Docket) processor.getContext().getBean(docketName);
// 修改docket分组信息
ApiSelectorBuilder apiSelectorBuilder = injectDocket.groupName(docketMap.get("group"))
.select()
.apis(RequestHandlerSelectors.basePackage(docketMap.get("api")));
// 判断是否有路径匹配信息
if (docketMap.containsKey("paths")) {
String[] pathArray = docketMap.get("paths").split(",");
String path;
String firstPath = pathArray[0];
Predicate<String> predicate;
// 模糊匹配路径,如/api/test/.*
if (firstPath.contains("*")) {
predicate = PathSelectors.regex(pathArray[0]);
// 精确匹配,如/api/test/log
} else {
predicate = PathSelectors.ant(pathArray[0]);
}
Predicate<String> orPredicate;
for (int i = 1; i < pathArray.length; i++) {
path = pathArray[i];
if (path.contains("*")) {
orPredicate = PathSelectors.regex(path);
} else {
orPredicate = PathSelectors.ant(path);
}
predicate = predicate.or(orPredicate);
}
apiSelectorBuilder.paths(predicate);
} else {
apiSelectorBuilder.paths(PathSelectors.any());
}
apiSelectorBuilder.build()
.apiInfo(apiInfo(docketMap));
}
}
/**
* Generate root bean definition root bean definition.
*
* @param docket the docket
* @return the root bean definition
*/
private RootBeanDefinition generateRootBeanDefinition(Map<String, String> docket) {
// 构造docket BeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition(Docket.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, DocumentationType.SWAGGER_2);
return beanDefinition;
}
/**
* Api info api info.
*
* @param docket the docket
* @return the api info
*/
private ApiInfo apiInfo(Map<String, String> docket) {
String contact = docket.get("contact");
// 构造接口文档基础信息
return new ApiInfoBuilder()
.title(docket.get("title"))
.description(docket.get("description"))
.termsOfServiceUrl(docket.get("termsOfServiceUrl"))
.contact(new Contact(contact, "", ""))
.version(docket.get("version"))
.build();
}
}
2.3.具体配置文件示例如下:
swagger: docket: - group: 接口文档分组1 api: com.demo.controller title: 对外接口文档 description: 对外接口文档 termsOfServiceUrl: http://${spring.cloud.client.ip-address}:${server.port}${server.servlet.context-path}/doc.html contact: sxp version: 1.0.0 # 需要显示的路径,如果全部显示,直接去掉这个配置即可 paths: /syslog/.* - group: 接口文档分组2 api: com.demo.controller title: 对外接口文档 description: 对外接口文档 termsOfServiceUrl: http://${spring.cloud.client.ip-address}:${server.port}${server.servlet.context-path}/doc.html contact: sxp version: 1.0.0 paths: /syslog/.*
2.4.配置后,启动服务查看swagger的效果如下: