前面在使用Swagger2時遇到的坑中簡單介紹了Swagger的使用。
不過默認情況下,Swagger2會把項目中的所有接口都展示在列表里,特別是你用了Springboot/SpringCloud之后,各種內部health check的接口,但其實這些都沒必要展示出來。
這時候,你就需要限定接口的范圍了。
實現方法
增加一個配置類,簡要代碼如下:
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket buildDocket() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
.apis(RequestHandlerSelectors.basePackage("com.yejg")).paths(PathSelectors.any()).build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("接口文檔").description("描述文字...").termsOfServiceUrl("https://yejg.top").version("V1.0").build();
}
}
有了這個【RequestHandlerSelectors.basePackage("com.yejg")】限定之后,就只會展示【com.yejg】包下的接口了。so easy…
不過,這時候,有個新問題,如果要增加展示 com.springXXX 的接口,怎么辦呢?
優化方案
直接上代碼之前,先看下優化方案怎么來的。
從代碼看,跟目錄范圍相關的就是apis方法了,源碼如下:
// 此Predicate是com.google.common.base.Predicate,不是jdk8的那個,不過原理類似 都是判斷的謂詞
public ApiSelectorBuilder apis(Predicate<RequestHandler> selector) {
requestHandlerSelector = and(requestHandlerSelector, selector);
return this;
}
想要支持配置多個目錄,就得從這個Predicate下手了。
先看下RequestHandlerSelectors.basePackage是怎么返回Predicate的:
public static Predicate<RequestHandler> basePackage(final String basePackage) {
return new Predicate<RequestHandler>() {
@Override
public boolean apply(RequestHandler input) {
return declaringClass(input).transform(handlerPackage(basePackage)).or(true);
}
};
}
private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
return new Function<Class<?>, Boolean>() {
@Override
public Boolean apply(Class<?> input) {
return input.getPackage().getName().startsWith(basePackage);
}
};
}
重點關注上面的handlerPackage方法,它的邏輯就是:判斷項目的包路徑是否以設定的basePackage開頭。
如果改變這里的判斷邏輯,判斷項目的包路徑是否以設定的basePackage1 或者 basePackage2 開頭,那就達到同時指定多個目錄的效果了。
實現代碼如下:
@Configuration
@EnableSwagger2
public class Swagger2Config {
// 定義分隔符
private static final String SEPARATOR = ",";
@Bean
public Docket buildDocket() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
.apis(basePackage("com.yejg" + SEPARATOR + "com.springXXX"))
.paths(PathSelectors.any()).build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("接口文檔").description("描述文字...")
.termsOfServiceUrl("https://yejg.top").version("V1.0").build();
}
/**
* @param basePackage
* @return
* @see RequestHandlerSelectors#basePackage(String)
*/
public static Predicate<RequestHandler> basePackage(final String basePackage) {
return new Predicate<RequestHandler>() {
@Override
public boolean apply(RequestHandler input) {
return declaringClass(input).transform(handlerPackage(basePackage)).or(true);
}
};
}
private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
return input -> {
// 循環判斷匹配
for (String strPackage : basePackage.split(SEPARATOR)) {
boolean isMatch = input.getPackage().getName().startsWith(strPackage);
if (isMatch) {
return true;
}
}
return false;
};
}
private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
return Optional.fromNullable(input.declaringClass());
}
}