Swagger是一款接口文档生成工具,可以根据Java代码中的注解来生成对应的接口文档,节省了我们编写接口文档的时间,而且随着接口的变动,文档跟着同步更新,非常方便
网上有很多集成Swagger的例子,都是简单的集成到项目里面就完了
其实我们在实际工作中还有一种需求,就是随着项目版本的迭代,接口的数量会越来越多,那如何管理这些接口就成了一个问题?
一般我们在进行版本迭代的时候都有版本号的概念,如果把版本号加到swagger接口文档中,那么我们就可以清晰的知道每次版本迭代新增或者修改了哪些接口,这样测试在评估测试范围的时候也会很方便,那接下来我们就在swagger里面加入版本号
引入Swagger相关的包
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.6.1'
compile group: 'io.springfox', name: 'springfox-spi', version: '2.6.1'
进行Swagger相关配置
@Bean
public Docket createApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("所有接口")
.select()
.apis(RequestHandlerSelectors.basePackage("com.kxg.demo"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder().title("××系统接口文档")
.description("接口文档").version("0.0.1").build();
}
完善接口注解
@Api("订单接口")
@RestController
public class OrderController {
@ApiVersion(value = VersionContent.VERSION_0_0_2)
@ApiOperation(value = "订单查询接口",notes = "查询用户的订单",httpMethod = "GET")
@RequestMapping(value = "/order/index.htm",method = RequestMethod.GET)
public String index(){
return "Hello World";
}
}
网上很多教程到这一步就完成了,其实这是最简单的swagger集成,下面我们把这个简单版升级一下,变成我们带版本号的方式
1、Swagger2配置
@Configuration
@EnableSwagger2
public class Swagger2Config implements InitializingBean {
@Autowired
private ApplicationContext applicationContext;
@Bean
public Docket createApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("所有接口")
.select()
.apis(RequestHandlerSelectors.basePackage("com.kxg.demo"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder().title("××系统接口文档")
.description("接口文档").version("0.0.1").build();
}
private Docket buildDocket(String groupName) {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName(groupName)
.select()
.apis(method ->{
if(method.isAnnotatedWith(ApiVersion.class)) {
ApiVersion apiVersion = method.getHandlerMethod().getMethodAnnotation(ApiVersion.class);
if (apiVersion.value() != null && apiVersion.value().length != 0) {
if (Arrays.asList(apiVersion.value()).contains(groupName)) {
return true;
}
}
}
ApiVersion annotationOnClass = method.getHandlerMethod().getBeanType().getAnnotation(ApiVersion.class);
if (annotationOnClass != null) {
if (annotationOnClass.value() != null && annotationOnClass.value().length != 0) {
if (Arrays.asList(annotationOnClass.value()).contains(groupName)) {
return true;
}
}
}
return false;
})
.paths(PathSelectors.any())
.build();
}
@Override
public void afterPropertiesSet() throws Exception {
// VersionContent 里面定义的每个变量会成为一个docket
Class<VersionContent> clazz = VersionContent.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()
.setFactoryMethodOnBean("buildDocket", "swagger2Config")
.addConstructorArgValue(declaredField.get(VersionContent.class)).getBeanDefinition();
capableBeanFactory.registerBeanDefinition(declaredField.getName(), beanDefinition);
}
}
}
}
2、静态资源配置
注意,这一步如果不配的话,你是访问不到swagger-ui.html这个页面的
@Configuration
public class ResourceConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/statics/");
registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
3、定义一个版本号的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ApiVersion {
String[] value();
}
4、定义一个版本号常量
public interface VersionContent {
String VERSION_0_0_1 = "v0.0.1";
String VERSION_0_0_2 = "v0.0.2";
}
5、写两个接口测试一下
我们写两个接口,在上面打上不同的版本号
@Api("订单接口")
@RestController
public class OrderController {
@ApiVersion(value = VersionContent.VERSION_0_0_2)
@ApiOperation(value = "订单查询接口",notes = "查询用户的订单",httpMethod = "GET")
@RequestMapping(value = "/order/index.htm",method = RequestMethod.GET)
public String index(){
return "Hello World";
}
}
@Api("用户接口")
@RestController
public class UserController {
@ApiVersion(value = VersionContent.VERSION_0_0_1)
@ApiOperation(value = "用户列表接口",notes = "查询所有用户",httpMethod = "GET")
@RequestMapping(value = "/user/index.htm",method = RequestMethod.GET)
public String index(){
return "Hello World";
}
}
@SpringBootApplication
public class SwaggerApplication {
public static void main(String[] args){
SpringApplication.run(SwaggerApplication.class, args);
}
}
另外,最后我们顺便把swagger-ui的页面也换掉,使用起来不方便
引入新的ui插件
compile group: 'com.github.xiaoymin', name: 'swagger-bootstrap-ui', version: '1.9.6'
静态资源配置需要修改一下
@Configuration
public class ResourceConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/statics/");
//此处要将swagger-ui.html换成doc.html
registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
最后启动项目,访问http://localhost:8080/doc.html
可以根据不同的版本号来显示对应的接口
关注公众号,回复“源码222”可免费下载Swagger2集成项目源码