废话不多说 先上代码
@Configuration
@EnableSwagger2
public class Swagger2Configuration {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(withClassAnnotation(Api.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("学习。。。")
.description("这个coder很懒")
.version("1.0")
.build();
}
/**
* 所有标识了@Api注解的类都要被扫描到,
*
* @return
*/
public Predicate withClassAnnotation(final Class<? extends Annotation>... annotations) {
return (input) -> declaringClass((RequestHandler) input).transform(annotationPresent(annotations)).or(false);
}
private static Function<Class<?>, Boolean> annotationPresent(final Class<? extends Annotation>... annotations) {
return input -> hasAnyAnnotation(input, annotations);
}
/**
* 当前类或者其父类、接口是否存在当前注解中的任意一个
* @param clazz 当前类
* @param annotations 目标接口
* @return
*/
private static boolean hasAnyAnnotation(Class clazz, final Class<? extends Annotation>... annotations) {
boolean include;
for (Class<? extends Annotation> annotation : annotations) {
include = clazz.isAnnotationPresent(annotation);
if (!include) {
// 判断实现的接口是否有继承
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> anInterface : interfaces) {
include = anInterface.isAnnotationPresent(annotation);
}
}
if (!include) {
Class superclass = clazz.getSuperclass();
if(!Object.class.equals(superclass)){
return hasAnyAnnotation(superclass,annotations);
}
}
if (include) {
return true;
}
}
return false;
}
private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
return Optional.fromNullable(input.declaringClass());
}
}
为什么有这个需求
我们通常会将一些公用的东西放在common模块,然后业务模块引用公用模块,
再来看下我们常用的配置方式
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("daisy.framework.api"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("学习。。。")
.description("这个coder很懒")
.version("1.0")
.build();
}
按照上面这种配置的话,现在我们有一个业务的包名是daisy.combat.xxx.controller 那么是不是意味者我们需要给上面的daisy.framework.api换成新的daisy.combat.xxx.controller,这个时候就有一个问题了,我们的项目是分模块开发,通用模块会被很多模块引用,所以我们不能使用硬编码的形式去解决它。
解决方案:
- 使用配置动态设置basePackage的值,这个时候需要解决配置多个路径的问题
- 扫描添加了指定注解的类、接口等。。。本文就是从这个思路出发
使用
我们可以自定义一个Api接口,当我们需要将它暴露给丝袜哥的时候,只需要给它或者它的父类添加该注解即可,这样的话不管我们的公用模块被什么业务模块使用,对于公用模块而言都不用理会。