add 插件日志
parent
80fc742f4a
commit
df2872a980
|
@ -71,6 +71,7 @@ public class SwaggerConfig {
|
|||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
.title(applicationName)
|
||||
.termsOfServiceUrl("http://ip:port/**")
|
||||
.description("Swagger API Doc")
|
||||
.build();
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
<java-semver.version>0.9.0</java-semver.version>
|
||||
<junit.version>4.11</junit.version>
|
||||
<spring-web.version>5.3.27</spring-web.version>
|
||||
<swagger-spring-web.version>2.10.5</swagger-spring-web.version>
|
||||
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -84,6 +86,12 @@
|
|||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
<version>2.0.9</version>
|
||||
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -23,16 +23,20 @@
|
|||
|
||||
package com.gitee.starblues.integration;
|
||||
|
||||
import com.gitee.starblues.integration.listener.SwaggerListener;
|
||||
import com.gitee.starblues.spring.ResolvePluginThreadClassLoader;
|
||||
import com.gitee.starblues.spring.web.PluginStaticResourceConfig;
|
||||
import com.gitee.starblues.spring.web.PluginStaticResourceWebMvcConfigurer;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.resource.ResourceResolver;
|
||||
import springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper;
|
||||
|
||||
/**
|
||||
* 系统web环境配置点
|
||||
|
@ -42,6 +46,7 @@ import org.springframework.web.servlet.resource.ResourceResolver;
|
|||
@ConditionalOnWebApplication
|
||||
@Import({
|
||||
ExtendPointWebConfiguration.PluginStaticResourceConfiguration.class,
|
||||
ExtendPointWebConfiguration.SwaggerListenerConfiguration.class,
|
||||
})
|
||||
public class ExtendPointWebConfiguration {
|
||||
|
||||
|
@ -62,6 +67,24 @@ public class ExtendPointWebConfiguration {
|
|||
}
|
||||
}
|
||||
|
||||
@ConditionalOnClass({ DocumentationPluginsBootstrapper.class })
|
||||
@ConditionalOnProperty(name = "plugin.pluginSwaggerScan", havingValue = "true", matchIfMissing = true)
|
||||
public static class SwaggerListenerConfiguration {
|
||||
|
||||
private final GenericApplicationContext applicationContext;
|
||||
|
||||
public SwaggerListenerConfiguration(GenericApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SwaggerListener swaggerListener(){
|
||||
return new SwaggerListener(applicationContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebMvcConfigurer webMvcConfigurer(){
|
||||
return new ResolvePluginThreadClassLoader();
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
package com.gitee.starblues.integration.listener;
|
||||
|
||||
import com.gitee.starblues.utils.SpringBeanUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
|
@ -33,8 +34,10 @@ import org.springframework.context.ApplicationContext;
|
|||
*/
|
||||
public class DefaultInitializerListener implements PluginInitializerListener{
|
||||
|
||||
private final SwaggerListener swaggerListener;
|
||||
|
||||
public DefaultInitializerListener(ApplicationContext applicationContext) {
|
||||
this.swaggerListener = SpringBeanUtils.getExistBean(applicationContext, SwaggerListener.class);
|
||||
}
|
||||
|
||||
|
||||
|
@ -54,6 +57,9 @@ public class DefaultInitializerListener implements PluginInitializerListener{
|
|||
}
|
||||
|
||||
private void refresh(){
|
||||
if(swaggerListener != null){
|
||||
swaggerListener.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
/**
|
||||
* Copyright [2019-Present] [starBlues]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.gitee.starblues.integration.listener;
|
||||
|
||||
import com.gitee.starblues.core.PluginInfo;
|
||||
import com.gitee.starblues.core.descriptor.PluginDescriptor;
|
||||
import com.gitee.starblues.loader.utils.ObjectUtils;
|
||||
import com.gitee.starblues.utils.MsgUtils;
|
||||
import com.gitee.starblues.utils.SpringBeanUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.plugin.core.PluginRegistry;
|
||||
import org.springframework.plugin.core.PluginRegistrySupport;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.service.Contact;
|
||||
import springfox.documentation.service.Parameter;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spi.service.DocumentationPlugin;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Swagger 监听事件
|
||||
* @author starBlues
|
||||
* @since 3.0.0
|
||||
* @version 3.0.3
|
||||
*/
|
||||
public class SwaggerListener implements PluginListener{
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
private final ApplicationContext mainApplicationContext;
|
||||
private static List<Parameter> parameterList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 设置全局头部/参数
|
||||
* ParameterBuilder tokenPar = new ParameterBuilder();
|
||||
* tokenPar.name("参数名称")
|
||||
* .description("参数描述")
|
||||
* .modelRef(new ModelRef("参数数据类型"))
|
||||
* .parameterType("header或者query等")
|
||||
* .required(false);
|
||||
* Parameter param = tokenPar.build();
|
||||
* @param parameters parameters
|
||||
*/
|
||||
public static void setParameters(List<Parameter> parameters){
|
||||
parameterList = parameters;
|
||||
}
|
||||
|
||||
public SwaggerListener(ApplicationContext mainApplicationContext) {
|
||||
this.mainApplicationContext = mainApplicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSuccess(PluginInfo pluginInfo) {
|
||||
PluginDescriptor descriptor = pluginInfo.getPluginDescriptor();
|
||||
try {
|
||||
Docket docket = this.createDocket(descriptor);
|
||||
String groupName = docket.getGroupName();
|
||||
PluginRegistry<DocumentationPlugin, DocumentationType> pluginRegistry = this.getPluginRegistry();
|
||||
List<DocumentationPlugin> plugins = pluginRegistry.getPlugins();
|
||||
List<DocumentationPlugin> newPlugins = new ArrayList<>();
|
||||
for(DocumentationPlugin plugin : plugins){
|
||||
if(plugin.getGroupName().equals(groupName)){
|
||||
continue;
|
||||
}
|
||||
newPlugins.add(plugin);
|
||||
}
|
||||
newPlugins.add(docket);
|
||||
|
||||
Field field = PluginRegistrySupport.class.getDeclaredField("plugins");
|
||||
field.setAccessible(true);
|
||||
field.set(pluginRegistry, newPlugins);
|
||||
// 如果第一次启动且为跟随系统启动的插件,减少刷新
|
||||
if(!pluginInfo.isFollowSystem() || pluginInfo.getStopTime() != null){
|
||||
this.refresh();
|
||||
}
|
||||
log.debug("插件[{}]注册到 Swagger 成功", MsgUtils.getPluginUnique(descriptor));
|
||||
} catch (Exception e) {
|
||||
log.error("插件[{}]注册到 Swagger 失败,错误为:{}", MsgUtils.getPluginUnique(descriptor) ,e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopSuccess(PluginInfo pluginInfo) {
|
||||
PluginDescriptor descriptor = pluginInfo.getPluginDescriptor();
|
||||
String groupName = getGroupName(descriptor);
|
||||
try{
|
||||
PluginRegistry<DocumentationPlugin, DocumentationType> pluginRegistry = this.getPluginRegistry();
|
||||
List<DocumentationPlugin> plugins = pluginRegistry.getPlugins();
|
||||
List<DocumentationPlugin> newPlugins = new ArrayList<>();
|
||||
for(DocumentationPlugin plugin : plugins){
|
||||
if(groupName.equalsIgnoreCase(plugin.getGroupName())){
|
||||
continue;
|
||||
}
|
||||
newPlugins.add(plugin);
|
||||
}
|
||||
|
||||
Field field = PluginRegistrySupport.class.getDeclaredField("plugins");
|
||||
field.setAccessible(true);
|
||||
field.set(pluginRegistry, newPlugins);
|
||||
|
||||
this.refresh();
|
||||
log.debug("插件[{}]从 Swagger 移除成功", MsgUtils.getPluginUnique(descriptor));
|
||||
} catch (Exception e) {
|
||||
log.error("插件[{}]从 Swagger 移除失败,错误为:{}", MsgUtils.getPluginUnique(descriptor), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
void refresh(){
|
||||
try {
|
||||
DocumentationPluginsBootstrapper documentationPluginsBootstrapper = this.getDocumentationPluginsBootstrapper();
|
||||
if(documentationPluginsBootstrapper != null){
|
||||
documentationPluginsBootstrapper.stop();
|
||||
documentationPluginsBootstrapper.start();
|
||||
} else {
|
||||
log.warn("Not found DocumentationPluginsBootstrapper, so cannot refresh swagger");
|
||||
}
|
||||
} catch (Exception e){
|
||||
// ignore
|
||||
log.warn("refresh swagger failure. {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文档 Bootstrapper
|
||||
* @return DocumentationPluginsBootstrapper
|
||||
*/
|
||||
private DocumentationPluginsBootstrapper getDocumentationPluginsBootstrapper(){
|
||||
return SpringBeanUtils.getExistBean(mainApplicationContext, DocumentationPluginsBootstrapper.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文档PluginRegistry
|
||||
* @return PluginRegistry
|
||||
*/
|
||||
private PluginRegistry<DocumentationPlugin, DocumentationType> getPluginRegistry(){
|
||||
PluginRegistry<DocumentationPlugin, DocumentationType> registry =
|
||||
SpringBeanUtils.getExistBean(mainApplicationContext, "documentationPluginRegistry");
|
||||
if(registry != null){
|
||||
return registry;
|
||||
}
|
||||
throw new IllegalStateException("项目依赖的 Swagger 版本不支持刷新插件接口, 请切换版本");
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建swagger分组对象
|
||||
*
|
||||
* @param descriptor 插件信息
|
||||
* @return Docket
|
||||
*/
|
||||
private Docket createDocket(PluginDescriptor descriptor) {
|
||||
String description = descriptor.getDescription();
|
||||
if (ObjectUtils.isEmpty(description)) {
|
||||
description = descriptor.getPluginId();
|
||||
}
|
||||
|
||||
String provider = descriptor.getProvider();
|
||||
String pluginBootstrapClass = descriptor.getPluginBootstrapClass();
|
||||
String pluginClass = pluginBootstrapClass.substring(0, pluginBootstrapClass.lastIndexOf("."));
|
||||
Contact contact = new Contact(provider, "", "");
|
||||
ApiInfo apiInfo = new ApiInfoBuilder()
|
||||
.title(getGroupName(descriptor))
|
||||
.description(description)
|
||||
.contact(contact)
|
||||
.version(descriptor.getPluginVersion())
|
||||
.build();
|
||||
|
||||
Docket docket = (new Docket(DocumentationType.SWAGGER_2))
|
||||
.apiInfo(apiInfo).select()
|
||||
.apis(RequestHandlerSelectors.basePackage(pluginClass))
|
||||
.paths(PathSelectors.any()).build()
|
||||
.groupName(getGroupName(descriptor));
|
||||
|
||||
if(parameterList != null && !parameterList.isEmpty()){
|
||||
return docket.globalOperationParameters(parameterList);
|
||||
}
|
||||
return docket;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取组名称
|
||||
* @param descriptor 插件信息
|
||||
* @return 分组信息
|
||||
*/
|
||||
private String getGroupName(PluginDescriptor descriptor){
|
||||
return descriptor.getPluginId() +"@" + descriptor.getPluginVersion();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue