Spring boot集成Swagger,并配置多个扫描路径

1:认识Swagger

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。

作用:

1. 接口的文档在线自动生成。

2. 功能测试。

Swagger是一组开源项目,其中主要要项目如下:

  1. Swagger-tools:提供各种与Swagger进行集成和交互的工具。例如模式检验、Swagger 1.2文档转换成Swagger 2.0文档等功能。

  2. Swagger-core: 用于Java/Scala的的Swagger实现。与JAX-RS(Jersey、Resteasy、CXF...)、Servlets和Play框架进行集成。

  3. Swagger-js: 用于JavaScript的Swagger实现。

  4. Swagger-node-express: Swagger模块,用于node.js的Express web应用框架。

  5. Swagger-ui:一个无依赖的HTML、JS和CSS集合,可以为Swagger兼容API动态生成优雅文档。

  6. Swagger-codegen:一个模板驱动引擎,通过分析用户Swagger资源声明以各种语言生成客户端代码。

2:spring boot 集成 swagger

2.1 引入POM

  1. <!-- swagger2 -->
  2. <dependency>
  3. <groupId>io.springfox</groupId>
  4. <artifactId>springfox-swagger2</artifactId>
  5. <version>2.9.2</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>io.springfox</groupId>
  9. <artifactId>springfox-swagger-ui</artifactId>
  10. <version>2.9.2</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>com.github.caspar-chen</groupId>
  14. <artifactId>swagger-ui-layer</artifactId>
  15. <version>1.1.3</version>
  16. </dependency>

2.2 配置swagger

在Application.java同级或子包中创建SwaggerConfig.java

  1. package com.example.demo.swagger;
  2.  
  3. import org.springframework.context.annotation.Bean;
  4. import springfox.documentation.builders.ApiInfoBuilder;
  5. import springfox.documentation.builders.PathSelectors;
  6. import springfox.documentation.builders.RequestHandlerSelectors;
  7. import springfox.documentation.service.ApiInfo;
  8. import springfox.documentation.spi.DocumentationType;
  9. import springfox.documentation.spring.web.plugins.Docket;
  10.  
  11. @Configuration
  12. @EnableSwagger2
  13. public class SwaggerConfig {
  14.  
  15. /**
  16. * 创建API应用
  17. * apiInfo() 增加API相关信息
  18. * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
  19. * 本例采用指定扫描的包路径来定义指定要建立API的目录。
  20. *
  21. * @return
  22. */
  23. @Bean
  24. public Docket createRestApi() {
  25. return new Docket(DocumentationType.SWAGGER_2)
  26. .apiInfo(apiInfo())
  27. .select()
  28. .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
  29. .paths(PathSelectors.any())
  30. .build();
  31. }
  32.  
  33. /**
  34. * 创建该API的基本信息(这些基本信息会展现在文档页面中)
  35. * 访问地址:http://项目实际地址/swagger-ui.html
  36. *
  37. * @return
  38. */
  39. private ApiInfo apiInfo() {
  40. return new ApiInfoBuilder()
  41. .title("测试 APIs")
  42. .description("测试api接口文档")
  43. .termsOfServiceUrl("http://www.baidu.com")
  44. .version("1.0")
  45. .build();
  46. }
  47. }

2.3 添加文档内容

在完成了上述配置后,其实已经可以生产文档内容,我们访问http://localhost:8080/swagger-ui.html。如图

 
1539140458684.png

但是这样的文档主要针对请求本身,描述的主要来源是函数的命名,对用户并不友好,我们通常需要自己增加一些说明来丰富文档内容。

Swagger使用的注解及其说明:

@Api:用在类上,说明该类的作用。

@ApiOperation:注解来给API增加方法说明。

@ApiImplicitParams : 用在方法上包含一组参数说明。

@ApiImplicitParam:用来注解来给方法入参增加说明。

@ApiResponses:用于表示一组响应

@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息

​ l code:数字,例如400

​ l message:信息,例如"请求参数没填好"

​ l response:抛出异常的类

@ApiModel:描述一个Model的信息(一般用在请求参数无法使用@ApiImplicitParam注解进行描述的时候)

​ l @ApiModelProperty:描述一个model的属性

例如:

  1. package com.example.demo.controller;
  2.  
  3. import com.example.demo.entity.User;
  4. import com.example.demo.service.UserService;
  5. import io.swagger.annotations.Api;
  6. import io.swagger.annotations.ApiOperation;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.web.bind.annotation.GetMapping;
  9. import org.springframework.web.bind.annotation.RequestMapping;
  10. import org.springframework.web.bind.annotation.RestController;
  11.  
  12. @RestController
  13. @RequestMapping("/user")
  14. @Api(tags="用户系统-用户管理")
  15. public class UserController {
  16.  
  17. @Autowired
  18. private UserService userService;
  19.  
  20. @GetMapping("updateMoblie")
  21. @ApiOperation(value="更新手机号", notes = "更新手机号接口")
  22. public String updateMoblie(Long userId){
  23. userService.updateMobile(userId);
  24. return "success";
  25. }
  26.  
  27. }

结果如图

 
1539140725037.png

以上我们完成了spring boot与swagger的集成,但是使用springfox中的 RequestHandlerSelectors.basePackage("com.xxx") 只能支持单个包路径的扫描匹配,如果我们业务中分了多个包,swagger怎么能扫描到呢?

3: swagger 多包扫描配置

要解决这个问题,我们可以参考一下RequestHandlerSelectors.basePackage的源码

  1. public class RequestHandlerSelectors {
  2. private RequestHandlerSelectors() {
  3. throw new UnsupportedOperationException();
  4. }
  5.  
  6. /**
  7. * Any RequestHandler satisfies this condition
  8. *
  9. * @return predicate that is always true
  10. */
  11. public static Predicate<RequestHandler> any() {
  12. return Predicates.alwaysTrue();
  13. }
  14.  
  15. /**
  16. * No RequestHandler satisfies this condition
  17. *
  18. * @return predicate that is always false
  19. */
  20. public static Predicate<RequestHandler> none() {
  21. return Predicates.alwaysFalse();
  22. }
  23.  
  24. /**
  25. * Predicate that matches RequestHandler with handlers methods annotated with given annotation
  26. *
  27. * @param annotation - annotation to check
  28. * @return this
  29. */
  30. public static Predicate<RequestHandler> withMethodAnnotation(final Class<? extends Annotation> annotation) {
  31. return new Predicate<RequestHandler>() {
  32. @Override
  33. public boolean apply(RequestHandler input) {
  34. return input.isAnnotatedWith(annotation);
  35. }
  36. };
  37. }
  38.  
  39. /**
  40. * Predicate that matches RequestHandler with given annotation on the declaring class of the handler method
  41. *
  42. * @param annotation - annotation to check
  43. * @return this
  44. */
  45. public static Predicate<RequestHandler> withClassAnnotation(final Class<? extends Annotation> annotation) {
  46. return new Predicate<RequestHandler>() {
  47. @Override
  48. public boolean apply(RequestHandler input) {
  49. return declaringClass(input).transform(annotationPresent(annotation)).or(false);
  50. }
  51. };
  52. }
  53.  
  54. private static Function<Class<?>, Boolean> annotationPresent(final Class<? extends Annotation> annotation) {
  55. return new Function<Class<?>, Boolean>() {
  56. @Override
  57. public Boolean apply(Class<?> input) {
  58. return input.isAnnotationPresent(annotation);
  59. }
  60. };
  61. }
  62.  
  63. private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
  64. return new Function<Class<?>, Boolean>() {
  65. @Override
  66. public Boolean apply(Class<?> input) {
  67. return ClassUtils.getPackageName(input).startsWith(basePackage);
  68. }
  69. };
  70. }
  71.  
  72. /**
  73. * Predicate 匹配RequestHandler,并为处理程序方法的类提供基本包名.
  74. * predicate 包括与所提供的basePackage匹配的所有请求处理程序
  75. *
  76. * @param basePackage - base package of the classes
  77. * @return this
  78. */
  79. public static Predicate<RequestHandler> basePackage(final String basePackage) {
  80. return new Predicate<RequestHandler>() {
  81. @Override
  82. public boolean apply(RequestHandler input) {
  83. return declaringClass(input).transform(handlerPackage(basePackage)).or(true);
  84. }
  85. };
  86. }
  87.  
  88. private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
  89. return Optional.fromNullable(input.declaringClass());
  90. }
  91.  
  92. }

我们看到 swagger 是通过Predicate 的apply 方法的返回值来判断是非匹配的 我们可以通过改造basePackage方法来实现多包扫描,改造 SwaggerConfig 如下

  1. package com.hzcominfo.sinopec.pos;
  2.  
  3. import com.google.common.base.Function;
  4. import com.google.common.base.Optional;
  5. import com.google.common.base.Predicate;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. import springfox.documentation.RequestHandler;
  9. import springfox.documentation.builders.ApiInfoBuilder;
  10. import springfox.documentation.builders.PathSelectors;
  11. import springfox.documentation.service.ApiInfo;
  12. import springfox.documentation.service.Contact;
  13. import springfox.documentation.spi.DocumentationType;
  14. import springfox.documentation.spring.web.plugins.Docket;
  15. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  16.  
  17. @Configuration
  18. @EnableSwagger2
  19. public class Swagger2 {
  20.  
  21. // 定义分隔符
  22. private static final String splitor = ";";
  23.  
  24. /**
  25. * 创建API应用
  26. * api() 增加API相关信息
  27. * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
  28. * 本例采用指定扫描的包路径来定义指定要建立API的目录。
  29. *
  30. * @return
  31. */
  32. @Bean
  33. public Docket api() {
  34. return new Docket(DocumentationType.SWAGGER_2)
  35. .apiInfo(apiInfo())
  36. .select()
  37. .apis(basePackage("com.hzcominfo.sinopec.pos.web.controller.mobilev1"
  38. + splitor
  39. + "com.hzcominfo.sinopec.pos.web.controller.mobilev2.api"))
  40. .paths(PathSelectors.any())
  41. .build();
  42. }
  43.  
  44. //构建 api文档的详细信息函数,注意这里的注解引用的是哪个
  45. private ApiInfo apiInfo() {
  46. return new ApiInfoBuilder()
  47. //页面标题
  48. .title("XXX项目接口")
  49. //创建人
  50. .contact(new Contact("userName", "", "linzp@hzcominfo.com"))
  51. //版本号
  52. .version("1.0.0-SNAPSHOT")
  53. //描述
  54. .description("")
  55. .build();
  56. }
  57.  
  58. public static Predicate<RequestHandler> basePackage(final String basePackage) {
  59. return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true);
  60. }
  61.  
  62. private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
  63. return input -> {
  64. // 循环判断匹配
  65. for (String strPackage : basePackage.split(splitor)) {
  66. boolean isMatch = input.getPackage().getName().startsWith(strPackage);
  67. if (isMatch) {
  68. return true;
  69. }
  70. }
  71. return false;
  72. };
  73. }
  74.  
  75. private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
  76. return Optional.fromNullable(input.declaringClass());
  77. }
  78.  
  79. /**
  80. * swagger2原始ui
  81. * http://localhost:8080/swagger-ui.html
  82. *
  83. * swagger-ui-layer访问ui
  84. * http://localhost:8080/docs.html
  85. */
  86. }

swagger2:

swagger-ui-layer:

Spring boot集成Swagger2,并配置多个扫描路径,添加swagger-ui-layer的更多相关文章

  1. Spring Boot 集成 Swagger2 与配置 OAuth2.0 授权

    Spring Boot 集成 Swagger2 很简单,由于接口采用了OAuth2.0 & JWT 协议做了安全验证,使用过程中也遇到了很多小的问题,多次尝试下述配置可以正常使用. Maven ...

  2. SpringBoot集成Swagger2并配置多个包路径扫描

    1. 简介   随着现在主流的前后端分离模式开发越来越成熟,接口文档的编写和规范是一件非常重要的事.简单的项目来说,对应的controller在一个包路径下,因此在Swagger配置参数时只需要配置一 ...

  3. Spring boot集成swagger2

    一.Swagger2是什么? Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件. Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格 ...

  4. 解决Spring Boot集成Shiro,配置类使用Autowired无法注入Bean问题

    如题,最近使用spring boot集成shiro,在shiroFilter要使用数据库动态给URL赋权限的时候,发现 @Autowired 注入的bean都是null,无法注入mapper.搜了半天 ...

  5. Spring Boot 集成Swagger2生成RESTful API文档

    Swagger2可以在写代码的同时生成对应的RESTful API文档,方便开发人员参考,另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API. 使用Spring Boot可 ...

  6. Spring Boot 集成 Swagger2 教程

    上篇讲过 Spring Boot RESTful api ,这篇简单介绍下 SwaggerUI 在 Spring Boot 中的应用. Swagger 是一个规范和完整的框架,用于生成.描述.调用和可 ...

  7. spring boot 集成swagger2

    1  在pom.xml中加入Swagger2的依赖 <dependency> <groupId>io.springfox</groupId> <artifac ...

  8. Spring Boot之Swagger2集成

    一.Swagger2简单介绍 Swagger2,它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档.它既可以减少我们创建文档的工作量,同时 ...

  9. spring boot集成redis基础入门

    redis 支持持久化数据,不仅支持key-value类型的数据,还拥有list,set,zset,hash等数据结构的存储. 可以进行master-slave模式的数据备份 更多redis相关文档请 ...

随机推荐

  1. 【转载,备忘】SQL Server 更改跟踪(Chang Tracking)监控表数据

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 主要区别与对比(Compare) 实现监控表数据步骤(Process) 参考文献(Refere ...

  2. Java课堂笔记1

    1.  Java严格区分大小写 2.  一个源文件public主类名必须和文件名完全一致 3. 命名规则严格要求,字母.数字.下划线.美元符号$.下划线_组成,其中不能以数字开头,也不能使用Java的 ...

  3. centos7查看防火墙状态、关闭防火墙

    查看防火墙状态: firewall-cmd --state 关闭防火墙: systemctl stop firewalld.service 禁止firewall开机启动: systemctl disa ...

  4. vue中ref在input中详解

    当我们在项目中遇见文本输入框的时候,获取时刻输入框中的值 1.v-model <template> <input type="text" v-model=&quo ...

  5. t100 常用公用變數

    g_enterprise 目前的企業代碼,將限制使用者所能閱讀的資料內容g_prog 目前執行的作業編號,用於變換畫面顯示資料與產生系統資訊,不可變更g_code 目前執行的程式代碼(4gl)名稱,不 ...

  6. 记一次redis主从同步失败

    zabbix告警突然从某个时间点开始提示CPU使用高,网卡流量也一直居高不下. 首先查看redis日志,发现告警时间点redis主节点被重启了,发生了主备切换,并且在日志中发现这么一段 [3081] ...

  7. go 学习笔记 ----资源自动回收

    在释放局部资源时, 可以用defer管理 Go语言版本基于defer的Mutex用法 func safeRead(Mutex *mu) []byte { mu.Lock() defer mu.Unlo ...

  8. FORM表单 onclick()与onsubmit()

    FORM表单中onclick().submit()与onsubmit()的问题 最近遇到一次处理form数据的过滤,采用了button的onclick事件来检查,发现return false后表单仍然 ...

  9. Python基础知识(三)

    Python基础知识(三) 一丶整型 #二进制转成十进制的方法 # 128 64 32 16 8 4 2 1 1 1 1 1 1 1 例如数字5 : 101 #十进制转成二进制的方法 递归除取余数,从 ...

  10. if __name__ == '__main__' 该如何理解

    Python 中的 if __name__ == '__main__' 该如何理解 程序入口 对于很多编程语言来说,程序都必须要有一个入口,比如 C,C++,以及完全面向对象的编程语言 Java,C# ...