说明
基于 javadoc
无注解零入侵生成规范的 openapi
结构体。
文档工具使用
由于框架采用 openapi 行业规范 故市面上大部分的框架均支持 可自行选择
例如: apifox
apipost
postman
torna
knife4j
等 根据对应工具的文档接入即可
Swagger升级SpringDoc指南
常见功能如下 其他功能自行挖掘
注意: javadoc
只能替换基础功能 特殊功能还需要使用注解实现
swagger | springdoc | javadoc |
---|---|---|
@Api(name = “xxx”) | @Tag(name = “xxx”) | java类注释第一行 |
@Api(description= “xxx”) | @Tag(description= “xxx”) | java类注释 |
@ApiOperation | @Operation | java方法注释 |
@ApiIgnore | @Hidden | 无 |
@ApiParam | @Parameter | java方法@param参数注释 |
@ApiImplicitParam | @Parameter | java方法@param参数注释 |
@ApiImplicitParams | @Parameters | 多个@param参数注释 |
@ApiModel | @Schema | java实体类注释 |
@ApiModelProperty | @Schema | java属性注释 |
@ApiModelProperty(hidden = true) | @Schema(accessMode = READ_ONLY) | 无 |
@ApiResponse | @ApiResponse | java方法@return返回值注释 |
Maven依赖
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webmvc-core</artifactId>
<version>1.6.14</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-javadoc</artifactId>
<version>1.6.14</version>
</dependency>
swagger 配置属性
package com.ruoyi.framework.config.properties;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.tags.Tag;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* swagger 配置属性
*
* @author Lion Li
*/
@Data
@Component
@ConfigurationProperties(prefix = "springdoc")
public class SpringDocProperties {
/**
* 文档基本信息
*/
@NestedConfigurationProperty
private InfoProperties info = new InfoProperties();
/**
* 扩展文档地址
*/
@NestedConfigurationProperty
private ExternalDocumentation externalDocs;
/**
* 标签
*/
private List<Tag> tags = null;
/**
* 路径
*/
@NestedConfigurationProperty
private Paths paths = null;
/**
* 组件
*/
@NestedConfigurationProperty
private Components components = null;
/**
* <p>
* 文档的基础属性信息
* </p>
*
* @see io.swagger.v3.oas.models.info.Info
*
* 为了 springboot 自动生产配置提示信息,所以这里复制一个类出来
*/
@Data
public static class InfoProperties {
/**
* 标题
*/
private String title = null;
/**
* 描述
*/
private String description = null;
/**
* 联系人信息
*/
@NestedConfigurationProperty
private Contact contact = null;
/**
* 许可证
*/
@NestedConfigurationProperty
private License license = null;
/**
* 版本
*/
private String version = null;
}
}
Swagger 文档配置
package com.ruoyi.framework.config;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.properties.SpringDocProperties;
import com.ruoyi.framework.handler.OpenApiHandler;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import lombok.RequiredArgsConstructor;
import org.springdoc.core.*;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.OpenApiCustomiser;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springdoc.core.providers.JavadocProvider;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* Swagger 文档配置
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Configuration
@AutoConfigureBefore(SpringDocConfiguration.class)
@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
public class SpringDocConfig {
private final ServerProperties serverProperties;
@Bean
@ConditionalOnMissingBean(OpenAPI.class)
public OpenAPI openApi(SpringDocProperties properties) {
OpenAPI openApi = new OpenAPI();
// 文档基本信息
SpringDocProperties.InfoProperties infoProperties = properties.getInfo();
Info info = convertInfo(infoProperties);
openApi.info(info);
// 扩展文档信息
openApi.externalDocs(properties.getExternalDocs());
openApi.tags(properties.getTags());
openApi.paths(properties.getPaths());
openApi.components(properties.getComponents());
Set<String> keySet = properties.getComponents().getSecuritySchemes().keySet();
List<SecurityRequirement> list = new ArrayList<>();
SecurityRequirement securityRequirement = new SecurityRequirement();
keySet.forEach(securityRequirement::addList);
list.add(securityRequirement);
openApi.security(list);
return openApi;
}
private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {
Info info = new Info();
info.setTitle(infoProperties.getTitle());
info.setDescription(infoProperties.getDescription());
info.setContact(infoProperties.getContact());
info.setLicense(infoProperties.getLicense());
info.setVersion(infoProperties.getVersion());
return info;
}
/**
* 自定义 openapi 处理器
*/
@Bean
public OpenAPIService openApiBuilder(Optional<OpenAPI> openAPI,
SecurityService securityParser,
SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils,
Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers,
Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomisers, Optional<JavadocProvider> javadocProvider) {
return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider);
}
/**
* 对已经生成好的 OpenApi 进行自定义操作
*/
@Bean
public OpenApiCustomiser openApiCustomiser() {
String contextPath = serverProperties.getServlet().getContextPath();
String finalContextPath;
if (StringUtils.isBlank(contextPath) || "/".equals(contextPath)) {
finalContextPath = "";
} else {
finalContextPath = contextPath;
}
// 对所有路径增加前置上下文路径
return openApi -> {
Paths oldPaths = openApi.getPaths();
if (oldPaths instanceof PlusPaths) {
return;
}
PlusPaths newPaths = new PlusPaths();
oldPaths.forEach((k,v) -> newPaths.addPathItem(finalContextPath + k, v));
openApi.setPaths(newPaths);
};
}
/**
* 单独使用一个类便于判断 解决springdoc路径拼接重复问题
*
* @author Lion Li
*/
static class PlusPaths extends Paths {
public PlusPaths() {
super();
}
}
}
自定义 openapi 处理器
package com.ruoyi.framework.handler;
import cn.hutool.core.io.IoUtil;
import io.swagger.v3.core.jackson.TypeNameResolver;
import io.swagger.v3.core.util.AnnotationsUtils;
import io.swagger.v3.oas.annotations.tags.Tags;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.core.OpenAPIService;
import org.springdoc.core.PropertyResolverUtils;
import org.springdoc.core.SecurityService;
import org.springdoc.core.SpringDocConfigProperties;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
import org.springdoc.core.providers.JavadocProvider;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.method.HandlerMethod;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 自定义 openapi 处理器
* 对源码功能进行修改 增强使用
*/
@SuppressWarnings("all")
public class OpenApiHandler extends OpenAPIService {
/**
* The constant LOGGER.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(OpenAPIService.class);
/**
* The Context.
*/
private ApplicationContext context;
/**
* The Security parser.
*/
private final SecurityService securityParser;
/**
* The Mappings map.
*/
private final Map<String, Object> mappingsMap = new HashMap<>();
/**
* The Springdoc tags.
*/
private final Map<HandlerMethod, io.swagger.v3.oas.models.tags.Tag> springdocTags = new HashMap<>();
/**
* The Open api builder customisers.
*/
private final Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomisers;
/**
* The server base URL customisers.
*/
private final Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers;
/**
* The Spring doc config properties.
*/
private final SpringDocConfigProperties springDocConfigProperties;
/**
* The Open api.
*/
private OpenAPI openAPI;
/**
* The Cached open api map.
*/
private final Map<String, OpenAPI> cachedOpenAPI = new HashMap<>();
/**
* The Is servers present.
*/
private boolean isServersPresent;
/**
* The Server base url.
*/
private String serverBaseUrl;
/**
* The Property resolver utils.
*/
private final PropertyResolverUtils propertyResolverUtils;
/**
* The javadoc provider.
*/
private final Optional<JavadocProvider> javadocProvider;
/**
* The Basic error controller.
*/
private static Class<?> basicErrorController;
static {
try {
//spring-boot 2
basicErrorController = Class.forName("org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController");
} catch (ClassNotFoundException e) {
//spring-boot 1
try {
basicErrorController = Class.forName("org.springframework.boot.autoconfigure.web.BasicErrorController");
} catch (ClassNotFoundException classNotFoundException) {
//Basic error controller class not found
LOGGER.trace(classNotFoundException.getMessage());
}
}
}
/**
* Instantiates a new Open api builder.
*
* @param openAPI the open api
* @param securityParser the security parser
* @param springDocConfigProperties the spring doc config properties
* @param propertyResolverUtils the property resolver utils
* @param openApiBuilderCustomizers the open api builder customisers
* @param serverBaseUrlCustomizers the server base url customizers
* @param javadocProvider the javadoc provider
*/
public OpenApiHandler(Optional<OpenAPI> openAPI, SecurityService securityParser,