上一篇提到了SpringBoot整合Swagger2,但現(xiàn)在微服務(wù)盛行,一個(gè)項(xiàng)目可能就要搭建許多微服務(wù),于是就想著將swagger2放到公共模塊中,到時(shí)候直接把包引入就能用?;旧虾蜕弦黄粯樱徊贿^(guò)就是把 swagger2的開(kāi)關(guān) 和 描述提取到了配置文件中,使得引入公共模塊的項(xiàng)目能在application.yml中控制swagger。
1. 需要了解的一些知識(shí)
- Springboot整合Swagger2 - 簡(jiǎn)書(shū) (jianshu.com)
- SpringBoot條件裝配
- SpringBoot配置文件中的數(shù)據(jù)格式
- SpringBoot讀取和使用配置文件中的數(shù)據(jù)
2. 1. 導(dǎo)包
<!--引入swagger -->
<!-- 排除springfox-swagger2 引入的swagger-annotations、swagger-models 1.5.20版本,手動(dòng)引入1.5.21版本的jar。
因?yàn)樵谑褂聾ApiModelProperty注解在字段上時(shí),如果字段的類型為L(zhǎng)ong或是int類型, 那么程序啟動(dòng)后,訪問(wèn)swagger-ui.html的頁(yè)面,
程序會(huì)報(bào)錯(cuò): java.lang.NumberFormatException: For input string: "" -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>
3. 配置
-
- 添加swagger屬性文件,以后在項(xiàng)目的application.yml文件中配置
@ConfigurationProperties(prefix = "swagger", ignoreUnknownFields = true) @Data public class SwaggerProperties { /** * 是否開(kāi)啟swagger,生產(chǎn)環(huán)境一般關(guān)閉,所以這里定義一個(gè)變量 */ private Boolean enable; /** * 文檔標(biāo)題 */ private String title; /** * 描述 */ private String description; /** * 版本號(hào) */ private String version; /** * api掃描包路徑 */ private String[] basePackage; /** * 是否開(kāi)啟head參數(shù) */ private Boolean headEnable = false; /** * head參數(shù) */ private List<HeadParam> headParams; } -
- 一個(gè)小類
@Data public class HeadParam { private String param; private Boolean required = false; } -
- swagger配置文件
import java.util.ArrayList; import java.util.List; 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.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import springfox.documentation.RequestHandler; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.ParameterBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.schema.ModelRef; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Parameter; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; /** * @ConditionalOnClass({Docket.class, ApiInfoBuilder.class}) 當(dāng)存在Docket和ApiInfoBuilder類的時(shí)候才加 載Bean; * @ConditionalOnMissingClass 不存在某個(gè)類的時(shí)候才會(huì)實(shí)例化Bean; * @ConditionalOnProperty(prefix = "swagger", value = "enable", matchIfMissing = true) * 當(dāng)存在swagger為前綴的屬性,才會(huì)實(shí)例化Bean; * @ConditionalOnMissingBean 當(dāng)不存在某個(gè)Bean的時(shí)候才會(huì)實(shí)例化; */ @Configuration @EnableSwagger2 @ConditionalOnClass({Docket.class, ApiInfoBuilder.class}) @ConditionalOnProperty(prefix = "swagger", value = "enable", matchIfMissing = true) @EnableConfigurationProperties(SwaggerProperties.class) public class SwaggerConfig { // 定義分隔符,配置Swagger多包 private static final String splitor = ";"; @Bean @ConditionalOnMissingBean public SwaggerProperties swaggerProperties() { return new SwaggerProperties(); } @Bean public Docket api() { SwaggerProperties properties = swaggerProperties(); // header參數(shù)設(shè)置 List<Parameter> headParams = new ArrayList<>(); List<HeadParam> hpList = properties.getHeadParams(); if (properties.getHeadEnable() == true && hpList.size() > 0) { for (HeadParam hp : hpList) { ParameterBuilder pb = new ParameterBuilder(); headParams.add( pb.name(hp.getParam()) .modelRef(new ModelRef("string")) .parameterType("header") .required(hp.getRequired()) .build()); } } // 掃描的包路徑 String[] basePackageList = properties.getBasePackage(); String basePackage = "xyz.2020555"; if (basePackageList != null && basePackageList.length > 0) { basePackage += ";" + ArrayUtil.join(basePackageList, ";"); } return new Docket(DocumentationType.SWAGGER_2) // 開(kāi)關(guān) .enable(properties.getEnable() == null?false:properties.getEnable()) .select() // 指定掃描1個(gè)包 // .apis(RequestHandlerSelectors.basePackage("com.test.controller")) // 掃描多包 .apis(scanBasePackage(basePackage)) // 只有標(biāo)記了@Api的類方法才會(huì)暴露出給swagger .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) // 只有標(biāo)記了@ApiOperation的方法才會(huì)暴露出給swagger .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) // 匹配路徑 .paths(PathSelectors.any()) .build() .globalOperationParameters(headParams) .apiInfo(apiInfo(properties)); } private ApiInfo apiInfo(SwaggerProperties properties) { return new ApiInfoBuilder() .title(properties.getTitle()) .description(properties.getDescription()) .version(properties.getVersion()) .build(); } /** * 切割掃描的包生成Predicate<RequestHandler> */ public static Predicate<RequestHandler> scanBasePackage(final String basePackage) { if (StrUtil.isBlank(basePackage)) { throw new NullPointerException("basePackage不能為空,多個(gè)包掃描使用" + splitor + "分隔"); } String[] controllerPack = basePackage.split(splitor); Predicate<RequestHandler> predicate = null; for (int i = controllerPack.length - 1; i >= 0; i--) { String strBasePackage = controllerPack[i]; if (StrUtil.isNotBlank(strBasePackage)) { Predicate<RequestHandler> tempPredicate = (Predicate<RequestHandler>) RequestHandlerSelectors .basePackage(strBasePackage); predicate = predicate == null ? tempPredicate : Predicates.or(tempPredicate, predicate); } } if (predicate == null) { throw new NullPointerException("basePackage配置不正確,多個(gè)包掃描使用" + splitor + "分隔"); } return predicate; } }
至此,公共模塊中swagger配置這樣的:

image.png
因?yàn)橐趛ml文件中配置swagger,所以在公共模塊
META-INF中加一些元數(shù)據(jù):additional-spring-configuration-metadata.json,非必須的,我用的eclipse,不想看見(jiàn)黃色感嘆號(hào),還能有提示
{"properties": [
{
"name": "swagger.enable",
"type": "java.lang.Boolean",
"description": "是否開(kāi)啟swagger'"
},
{
"name": "swagger.title",
"type": "java.lang.String",
"description": "文檔標(biāo)題'"
},
{
"name": "swagger.version",
"type": "java.lang.String",
"description": "版本號(hào)'"
},
{
"name": "swagger.description",
"type": "java.lang.String",
"description": "描述'"
},
{
"name": "swagger.head-enable",
"type": "java.lang.Boolean",
"description": "是否開(kāi)啟head參數(shù)'"
},
{
"name": "swagger.head-params",
"type": "java.util.List",
"description": "head參數(shù)'"
},
{
"name": "swagger.base-package",
"type": "java.util.List",
"description": "api掃描包路徑"
}
]}
我放到這了:

image.png
配置,到這就完成了。
4. 使用
使用時(shí),在其他微服務(wù)中導(dǎo)入公共模塊的jar包,然后在yml文件中配置。
# 5.swagger
swagger:
enable: true
title: ${spring.application.name}
version: 1.0
base-package:
- com.test.controller
description: 訪問(wèn)地址:http://192.168.50.30:${server.port}${server.servlet.context-path}
head-enable: true
head-params:
- param: token1
required: true
- param: token2
required: false
自己封裝自己用,可以自嗨了。。。。。。。