前面在使用Swagger2时遇到的坑中简单介绍了Swagger的使用。html
不过默认状况下,Swagger2会把项目中的全部接口都展现在列表里,特别是你用了Springboot/SpringCloud以后,各类内部health check的接口,但其实这些都不必展现出来。java
这时候,你就须要限定接口的范围了。spring
增长一个配置类,简要代码以下:api
@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…app
不过,这时候,有个新问题,若是要增长展现 com.springXXX 的接口,怎么办呢?ide
直接上代码以前,先看下优化方案怎么来的。优化
从代码看,跟目录范围相关的就是apis方法了,源码以下:ui
// 此Predicate是com.google.common.base.Predicate,不是jdk8的那个,不过原理相似 都是判断的谓词 public ApiSelectorBuilder apis(Predicate<RequestHandler> selector) { requestHandlerSelector = and(requestHandlerSelector, selector); return this; }
想要支持配置多个目录,就得从这个Predicate下手了。this
先看下RequestHandlerSelectors.basePackage是怎么返回Predicate的:google
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()); } }