Springboot+Swagger2新玩法,你Get到了吗?

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集成项目源码
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/pzjtian/article/details/106414666