springboot整合swagger配置在之前的文章已经写过了,此篇是基于已整合swagger后的,关于版本控制的配置和demo案例。
文章地址:swagger2 注解详解+使用案例
版本控制思路:
此demo是基于swagger的group进行版本控制,对接口URL无侵入,版本对接口地址无影响。
相关操作和注意项:
- 无新增依赖jar包;
- 新增自定义版本注解ApiVersion ;
- 新增版本号定义(常量或枚举值都行);
- 手动实例化Docket对象,并注入到spring容器;
- 相关解释都在代码注释里;
自定义版本注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ApiVersion {
/**
* 分组名(即版本号)
*
* @return
*/
String[] value() default CustomVersion.VERSION_1;
}
版本号
public interface CustomVersion {
String VERSION_1 = "v1";
String VERSION_2 = "v2";
}
无版本控制的配置
通过@Configuration + @Bean注解直接自动注入到spring容器中。
@Bean
public Docket docketDefault() {
// 设置要显示swagger的环境
// 通过 enable() 接收此参数判断是否要显示
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//不展示默认的Response信息
.useDefaultResponseMessages(false)
//默认为default
.groupName("all")
// 配置是否启用Swagger,如果是false,在浏览器将无法访问
// .enable(false)
// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
.select()
//配置你想在那个controller层生产接口文档
.apis(RequestHandlerSelectors.basePackage("ai.ecarx.data.syn.controller"))
// 配置如何通过path过滤,即这里只扫描请求以 /search 开头的接口
// .paths(PathSelectors.ant("/search/**"))
.build();
}
版本控制的配置(重点)
通过继承 InitializingBean 类,自动执行手动将Docket实例注入spring容器中。
@Configuration
public class SwaggerConfig implements InitializingBean {
@Autowired
private ApplicationContext applicationContext;
public Docket docketVersion(String groupName){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.useDefaultResponseMessages(false)
.groupName(groupName)
.select()
//版本控制
.apis(
method -> {
// 每个方法会进入这里进行判断并归类到不同分组,**请不要调换下面两段代码的顺序,在方法上的注解有优先级**
// 该方法上标注了版本
Optional<ApiVersion> methodAnnotation = method.findAnnotation(ApiVersion.class);
if (methodAnnotation.isPresent()) {
return Arrays.asList(methodAnnotation.get().value()).contains(groupName);
}
// controller上标注了版本
Optional<ApiVersion> controllerAnnotation = method.findControllerAnnotation(ApiVersion.class);
if (controllerAnnotation.isPresent()) {
return Arrays.asList(controllerAnnotation.get().value()).contains(groupName);
}
return false;
})
.build();
}
/**
* 动态得创建Docket bean
*
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
// ApiConstantVersion 里面定义的每个变量会成为一个docket
Class<CustomVersion> clazz = CustomVersion.class;
Field[] declaredFields = clazz.getDeclaredFields();
// 动态注入bean
AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
if (autowireCapableBeanFactory instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory capableBeanFactory = (DefaultListableBeanFactory) autowireCapableBeanFactory;
for (Field declaredField : declaredFields) {
// 要注意 "工厂名和方法名",意思是用这个bean的指定方法创建docket
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition()
//此处的swaggerConfig首字母要小写否则报找不到bean的方法
.setFactoryMethodOnBean("docketVersion", "swaggerConfig")
.addConstructorArgValue(declaredField.get(CustomVersion.class)).getBeanDefinition();
capableBeanFactory.registerBeanDefinition(declaredField.getName(), beanDefinition);
}
}
}
/**
* 配置文档信息
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.version("1.0")
.title("swagger API")
.description("接口描述")
.build();
}
}