OpenApi是业界真正的 api 文档标准,一个规范,好比java里面一个抽象的概念。
它即是一个抽象类,只是提供了一个api文档规范的抽象方法,该方法目前被两大非官方实现了,一个是springfox,另一个是springdoc。
删除springfox和swagger 2的依赖项。而是添加springdoc openapi用户界面依赖项。以下是当前最新版本
<dependency>
<groupId>org.springdocgroupId>
<artifactId>springdoc-openapi-uiartifactId>
<version>1.4.3version>
dependency>
@Api -> @Tag
@ApiIgnore -> @Parameter(hidden = true) or @Operation(hidden = true) or @Hidden
@ApiImplicitParam -> @Parameter
@ApiImplicitParams -> @Parameters
@ApiModel -> @Schema
@ApiModelProperty(hidden = true) -> @Schema(accessMode = READ_ONLY)
@ApiModelProperty -> @Schema
@ApiOperation(value = "foo", notes = "bar") -> @Operation(summary = "foo", description = "bar")
@ApiParam -> @Parameter
@ApiResponse(code = 404, message = "foo") -> @ApiResponse(responseCode = "404", description = "foo")
@Bean
public Docket publicApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.public"))
.paths(PathSelectors.regex("/public.*"))
.build()
.groupName("springshop-public")
.apiInfo(apiInfo());
}
@Bean
public Docket adminApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.admin"))
.paths(PathSelectors.regex("/admin.*"))
.build()
.groupName("springshop-admin")
.apiInfo(apiInfo());
}
需要替换成springdoc-openapi配置的GroupedOpenApi对象
@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.setGroup("springshop-public")
.pathsToMatch("/public/**")
.build();
}
@Bean
public GroupedOpenApi adminApi() {
return GroupedOpenApi.builder()
.setGroup("springshop-admin")
.pathsToMatch("/admin/**")
.build();
}
@Bean
public OpenAPI springShopOpenAPI() {
Components components = new Components();
// 添加auth认证header
components.addSecuritySchemes("auth", new SecurityScheme().type(SecurityScheme.Type.APIKEY).name("auth").in(In.HEADER).scheme("basic"));
// 添加全局header
components.addParameters("myHeader1", new Parameter().in(In.HEADER.toString()).schema(new StringSchema()).name("myHeader1"));
components.addHeaders("myHeader2", new Header().description("myHeader2 header").schema(new StringSchema()));
return new OpenAPI()
.components(components)
.info(new Info().title("Sinhy " + applicationName + " Api Doc")
.description(applicationDescription)
.version("Application Version: " + applicationVersion + "\n Spring Boot Version: " + SpringBootVersion.getVersion())
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("SpringShop Wiki Documentation")
.url("https://springshop.wiki.github.org/docs"));
}
public class SpringdocConfiguration implements WebMvcConfigurer
添加实现方法
/**
* 通用拦截器排除设置,所有拦截器都会自动加springdoc-opapi相关的资源排除信息,不用在应用程序自身拦截器定义的地方去添加,算是良心解耦实现。
*/
@SuppressWarnings("unchecked")
public void addInterceptors(InterceptorRegistry registry)
{
Field registrationsField = ClassUtils.getField(InterceptorRegistry.class, "registrations");
List<InterceptorRegistration> registrations = (List<InterceptorRegistration>) ReflectionUtils.getField(registrationsField, registry);
if (registrations != null)
{
for (InterceptorRegistration interceptorRegistration : registrations)
{
interceptorRegistration.excludePathPatterns("/springdoc**/**");
}
}
}
public class SpringdocConfiguration implements ApplicationListener<ContextRefreshedEvent>
{
添加实现方法
/**
* 系统启动后自动打开浏览器访问api-doc地址
* @author lilinhai
* @since 2020-07-17 15:53
* @param arg0
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent arg0)
{
StartupInformation.getInstance().setStartupTime(new Date());
if (PlatformUtils.isWindows())
{
// 如果rest-api开关打开,则启动完成后启动打开浏览器并浏览该rest-api主页
String baseUrl = "http://localhost:" + port;
if (!contextPath.startsWith("/"))
{
baseUrl += "/";
}
baseUrl += contextPath;
if (!baseUrl.endsWith("/"))
{
baseUrl += "/";
}
if (apiDocUiPath.startsWith("/"))
{
apiDocUiPath = apiDocUiPath.substring(1);
}
// 打开rest-api网址
String restApiUrl = baseUrl + apiDocUiPath;
BrowseUtils.browse(restApiUrl);
// 打开数据源监控网址
String datasourceMonitorUrl = baseUrl + "datasource-monitor/admin.html";
BrowseUtils.browse(datasourceMonitorUrl);
}
}
springdoc:
swagger-ui:
# 自定义的文档界面访问路径。默认访问路径是/swagger-ui.html
path: /springdoc/docs.html
# 字符串类型,一共三个值来控制操作和标记的默认展开设置。它可以是“list”(仅展开标记)、“full”(展开标记和操作)或“none”(不展开任何内容)。
docExpansion: none
# 布尔值。控制“试用”请求的请求持续时间(毫秒)的显示。
displayRequestDuration: true
# 布尔值。控制供应商扩展(x-)字段和操作、参数和架构值的显示。
showExtensions: true
# 布尔值。控制参数的扩展名(pattern、maxLength、minLength、maximum、minminimum)字段和值的显示。
showCommonExtensions: true
# 布尔值。禁用swagger用户界面默认petstore url。(从v1.4.1开始提供)。
disable-swagger-default-url: true
api-docs:
# 自定义的文档api元数据访问路径。默认访问路径是/v3/api-docs
path: /springdoc/api-docs
# 布尔值。在@Schema(名称name、标题title和说明description,三个属性)上启用属性解析程序。
resolve-schema-properties: true
# 布尔值。实现OpenApi规范的打印。
writer-with-default-pretty-printer: true
import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;
import org.apache.logging.log4j.core.config.Order;
import org.springdoc.core.Constants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.headers.Header;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.security.SecurityScheme.In;
import pers.linhai.nature.spring.YamlPropertySourceFactory;
import pers.linhai.nature.utils.BrowseUtils;
import pers.linhai.nature.utils.ClassUtils;
import pers.linhai.nature.utils.PlatformUtils;
import pers.linhai.nature.utils.ReflectionUtils;
import pers.linhai.nature.webmvc.controller.model.SystemInfo.StartupInformation;
/**
* Springdoc-openapi配置
*
* @author lilinhai
* @since 2020-07-13 10:46
* @version V1.0
*/
@Order(Integer.MAX_VALUE)
@Configuration
@ConditionalOnProperty(name = Constants.SPRINGDOC_ENABLED, havingValue = "true", matchIfMissing = true)
@PropertySource(value = "classpath:META-INF/springdoc.yml", factory = YamlPropertySourceFactory.class)
public class SpringdocOpenapiConfiguration implements WebMvcConfigurer, ApplicationListener<ContextRefreshedEvent>
{
/**
* 项目应用名
*/
@Value("${application.name}")
private String applicationName;
/**
* 项目版本信息
*/
@Value("${application.version}")
private String applicationVersion;
/**
* API文档访问地址
*/
@Value("${springdoc.swagger-ui.path}")
private String apiDocUiPath;
/**
* API文档访问地址
*/
@Value("${springdoc.api-docs.path}")
private String apiDocPath;
/**
* 项目描述信息
*/
@Value("${application.description}")
private String applicationDescription;
/**
* 上下文路径
*/
@Value("${server.servlet.context-path}")
private String contextPath;
/**
* web访问端口
*/
@Value("${server.port}")
private int port;
@Bean
public OpenAPI springShopOpenAPI() {
Components components = new Components();
// 添加auth认证header
components.addSecuritySchemes("auth", new SecurityScheme().type(SecurityScheme.Type.APIKEY).name("auth").in(In.HEADER).scheme("basic"));
// 添加全局header
components.addParameters("myHeader1", new Parameter().in(In.HEADER.toString()).schema(new StringSchema()).name("myHeader1"));
components.addHeaders("myHeader2", new Header().description("myHeader2 header").schema(new StringSchema()));
return new OpenAPI()
.components(components)
.info(new Info().title("Sinhy " + applicationName + " Api Doc")
.description(applicationDescription)
.version("Application Version: " + applicationVersion + "\n Spring Boot Version: " + SpringBootVersion.getVersion())
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("SpringShop Wiki Documentation")
.url("https://springshop.wiki.github.org/docs"));
}
/**
* 通用拦截器排除设置,所有拦截器都会自动加springdoc-opapi相关的资源排除信息,不用在应用程序自身拦截器定义的地方去添加,算是良心解耦实现。
*/
@SuppressWarnings("unchecked")
public void addInterceptors(InterceptorRegistry registry)
{
Field registrationsField = ClassUtils.getField(InterceptorRegistry.class, "registrations");
List<InterceptorRegistration> registrations = (List<InterceptorRegistration>) ReflectionUtils.getField(registrationsField, registry);
if (registrations != null)
{
for (InterceptorRegistration interceptorRegistration : registrations)
{
interceptorRegistration.excludePathPatterns("/springdoc**/**");
}
}
}
/**
* 系统启动后自动打开浏览器访问api-doc地址
* @author lilinhai
* @since 2020-07-17 15:53
* @param arg0
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent arg0)
{
StartupInformation.getInstance().setStartupTime(new Date());
if (PlatformUtils.isWindows())
{
// 如果rest-api开关打开,则启动完成后启动打开浏览器并浏览该rest-api主页
String baseUrl = "http://localhost:" + port;
if (!contextPath.startsWith("/"))
{
baseUrl += "/";
}
baseUrl += contextPath;
if (!baseUrl.endsWith("/"))
{
baseUrl += "/";
}
if (apiDocUiPath.startsWith("/"))
{
apiDocUiPath = apiDocUiPath.substring(1);
}
// 打开rest-api网址
String restApiUrl = baseUrl + apiDocUiPath;
BrowseUtils.browse(restApiUrl);
// 打开数据源监控网址
String datasourceMonitorUrl = baseUrl + "datasource-monitor/admin.html";
BrowseUtils.browse(datasourceMonitorUrl);
}
}
}