用于快速生成接口文档,并在线测试,接口文档也实时更新。官方链接https://swagger.io/

集成

官方starter

  1. <dependency>
  2. <groupId>io.springfox</groupId>
  3. <artifactId>springfox-boot-starter</artifactId>
  4. <version>3.0.0</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>io.swagger</groupId>
  8. <artifactId>swagger-models</artifactId>
  9. <version>1.6.2</version>
  10. </dependency>

访问如下地址

  1. http://localhost:8080/swagger-ui/index.html

Snipaste_2022-01-14_13-28-40.png

配置

需要将Swagger的Docket实例加到Spring容器中

  1. @Configuration
  2. public class SwaggerCfg {
  3. @Bean
  4. public Docket docket(){
  5. return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开"));
  6. }
  7. private ApiInfo apiInfo(String title, String desc) {
  8. Contact contact = new Contact("作者:李付发","http://www.baidu.com","1966591729@qq.com");
  9. return new ApiInfoBuilder()
  10. .title(title)
  11. .version("1.0.0")
  12. .description(desc)
  13. .contact(contact)
  14. .build();
  15. }
  16. }

image.png

配置要扫描的接口

关键角色:Docket的select方法

  1. @Configuration
  2. public class SwaggerCfg {
  3. @Bean
  4. public Docket docket(){
  5. return new Docket(DocumentationType.SWAGGER_2)
  6. .apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开"))
  7. .select()
  8. //RequestHandlerSelectors配置要扫描接口的方式,basePackage指定要扫描的包
  9. //.apis(RequestHandlerSelectors.basePackage("com.lff.dr"))
  10. //withMethodAnnotation扫描方法上的注解
  11. .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
  12. //过滤匹配
  13. .paths(PathSelectors.regex("/(xxx.)"))
  14. .build();
  15. }
  16. private ApiInfo apiInfo(String title, String desc) {
  17. Contact contact = new Contact("作者:李付发","http://www.baidu.com","1966591729@qq.com");
  18. return new ApiInfoBuilder()
  19. .title(title)
  20. .version("1.0.0")
  21. .description(desc)
  22. .contact(contact)
  23. .build();
  24. }
  25. }

开启和关闭Swagger功能

项目上线后我们应该关闭Swagger功能,防止通过Swagger来发起请求。Docket有个.enable方法用来设置是否开启。

  1. new Docket(DocumentationType.SWAGGER_2)
  2. .enable(false) //false表示开启,true表示关闭

image.png
思考:怎么根据项目的环境,也就是生产环境还是测试环境自动开启或关闭Swagger?
有一种比较好的方式是直接获取Spring配置文件中的如下内容

  1. spring:
  2. profiles:
  3. active: dev

看一下active的值是dev环境还是生产环境。Snipaste_2022-01-15_09-22-52.png

  1. @Bean
  2. public Docket docket(Environment environment){
  3. //获取配置文件激活的环境是否有dev,test
  4. Boolean enable = environment.acceptsProfiles(Profiles.of("dev","test"));
  5. return new Docket(DocumentationType.SWAGGER_2)
  6. .enable(enable)
  7. .apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开"))
  8. .select()
  9. //RequestHandlerSelectors配置要扫描接口的方式,basePackage指定要扫描的包
  10. //.apis(RequestHandlerSelectors.basePackage("com.lff.dr"))
  11. //withMethodAnnotation扫描方法上的注解
  12. .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
  13. .build();
  14. }

配置API文档分组

Docket有个groupName(“”)方法用于设置分组。

  1. new Docket(DocumentationType.SWAGGER_2)
  2. .groupName("数据字典分组")

image.png
思考:如何设置多个分组?
只需创建多个Docket Bean实例即可。

  1. @Configuration
  2. public class SwaggerCfg {
  3. @Bean
  4. public Docket userDocket(Environment environment){
  5. //获取配置文件激活的环境是否有dev,test
  6. Boolean enable = environment.acceptsProfiles(Profiles.of("dev","test"));
  7. return new Docket(DocumentationType.SWAGGER_2)
  8. .groupName("用户组")
  9. .enable(enable)
  10. .apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开"))
  11. .select()
  12. .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
  13. .build();
  14. }
  15. @Bean
  16. public Docket docket(Environment environment){
  17. //获取配置文件激活的环境是否有dev,test
  18. Boolean enable = environment.acceptsProfiles(Profiles.of("dev","test"));
  19. return new Docket(DocumentationType.SWAGGER_2)
  20. .groupName("数据字典分组")
  21. .enable(enable)
  22. .apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开"))
  23. .select()
  24. //RequestHandlerSelectors配置要扫描接口的方式,basePackage指定要扫描的包
  25. //.apis(RequestHandlerSelectors.basePackage("com.lff.dr"))
  26. //withMethodAnnotation扫描方法上的注解
  27. .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
  28. .build();
  29. }
  30. private ApiInfo apiInfo(String title, String desc) {
  31. Contact contact = new Contact("作者:李付发","http://www.baidu.com","1966591729@qq.com");
  32. return new ApiInfoBuilder()
  33. .title(title)
  34. .version("1.0.0")
  35. .description(desc)
  36. .contact(contact)
  37. .build();
  38. }
  39. }

image.png

忽略请求参数

Docket有个ignoredParameterTypes 方法用于设置忽略请求参数
比如我们的接口是这样写的

  1. @RestController
  2. @RequestMapping("/dictTypes")
  3. public class DictTypeController {
  4. @Autowired
  5. private DictTypeService service;
  6. @GetMapping("/list")
  7. @ApiOperation(value = "返回所有的数据字典类型",notes = "")
  8. public Map<String,Object> listAll(DictTypeQuery query, HttpSession session)
  9. {
  10. Map<String,Object> map = new HashMap<>();
  11. map.put("code",0);
  12. map.put("data",service.list());
  13. return map;
  14. }
  15. }

image.png
会发现把HttpSession里面的参数也生成了,我们可以对这些参数进行忽略

  1. @Bean
  2. public Docket docket(Environment environment){
  3. //获取配置文件激活的环境是否有dev,test
  4. Boolean enable = environment.acceptsProfiles(Profiles.of("dev","test"));
  5. return new Docket(DocumentationType.SWAGGER_2)
  6. .groupName("数据字典分组")
  7. .enable(enable)
  8. .ignoredParameterTypes(
  9. HttpSession.class,
  10. HttpServletRequest.class,
  11. HttpServletResponse.class)
  12. .apiInfo(apiInfo("牛逼的项目接口文档","小米也学牡丹开"))
  13. .select()
  14. //RequestHandlerSelectors配置要扫描接口的方式,basePackage指定要扫描的包
  15. //.apis(RequestHandlerSelectors.basePackage("com.lff.dr"))
  16. //withMethodAnnotation扫描方法上的注解
  17. .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
  18. .build();
  19. }

image.png

配置全局参数

我们有时需要配置全局参数,比如很多请求都需要传token参数,要求用户只有登录成功后才能访问资源(token一般是登录成功后返回给客户端的,客户端保存token)。
这时可以使用Docket的globalRequestParameters方法

  1. @Bean
  2. public Docket userDocket(Environment environment){
  3. //获取配置文件激活的环境是否有dev,test
  4. Boolean enable = environment.acceptsProfiles(Profiles.of("dev","test"));
  5. RequestParameter tokenParam = new RequestParameterBuilder()
  6. .name("Token") //参数的名称
  7. .description("用户登录令牌")
  8. .in(ParameterType.HEADER) //token放在请求头里面发送
  9. .build();
  10. return new Docket(DocumentationType.SWAGGER_2)
  11. .groupName("用户组")
  12. .enable(enable)
  13. .globalRequestParameters(List.of(tokenParam))
  14. .ignoredParameterTypes(
  15. HttpSession.class,
  16. HttpServletRequest.class,
  17. HttpServletResponse.class)
  18. .apiInfo(apiInfo("用户组模块","用户组描述"))
  19. .select()
  20. .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
  21. .build();
  22. }

image.png
这样就很方便的模拟有token的请求了

常用注解

@APi

  1. @Api(tags = "模块名") //用在Controller上

�实例

  1. @RestController
  2. @RequestMapping("/dictTypes")
  3. @Api(tags = "数据字典类型")
  4. public class DictTypeController {
  5. @Autowired
  6. private DictTypeService service;
  7. @GetMapping("/list")
  8. @ApiOperation(value = "返回所有的数据字典类型",notes = "")
  9. public Map<String,Object> listAll(DictTypeQuery query)
  10. {
  11. Map<String,Object> map = new HashMap<>();
  12. map.put("code",0);
  13. map.put("data",service.list());
  14. return map;
  15. }
  16. }

image.png

@ApiOperation

  1. @ApiOperation(value = "用途",notes = "备注")

实例

  1. @RestController
  2. @RequestMapping("/dictTypes")
  3. @Api(tags = "数据字典类型")
  4. public class DictTypeController {
  5. @Autowired
  6. private DictTypeService service;
  7. @GetMapping("/list")
  8. @ApiOperation(value = "返回所有的数据字典类型",notes = "可以传分页大小,第几页等")
  9. public Map<String,Object> listAll(DictTypeQuery query)
  10. {
  11. Map<String,Object> map = new HashMap<>();
  12. map.put("code",0);
  13. map.put("data",service.list());
  14. return map;
  15. }
  16. }

image.png

@ApiModel、@ApiModelProperty

  1. @ApiModel(value = "实体名称",description = "描述") //@ApiModel用在实体上
  2. @ApiModelProperty(value = "属性名描述",required = false,hidden = false) //@ApiModelProperty用在实体的属性上,required是否必传,hidden在Swagger是否显示

实例

  1. @ApiModel(value = "DictTypeQuery",description = "数据字典类型查询参数")
  2. public class DictTypeQuery {
  3. @ApiModelProperty(value = "搜索关键字",required = false)
  4. private String keyWord;
  5. @ApiModelProperty(value = "客户端传递的页码",required = true)
  6. private Long page;
  7. @ApiModelProperty(value = "每页多少条数据")
  8. private Long size;
  9. @ApiModelProperty(hidden = true)
  10. private List<?> data;
  11. //查询的总页数
  12. @ApiModelProperty(hidden = true)
  13. private Long total;
  14. //总页数
  15. @ApiModelProperty(hidden = true)
  16. private Long pages;
  17. }

image.png

@ApiParam

  1. @ApiParam(value = "请求参数描述",required = false,hidden = false)

实例

  1. @RestController
  2. @RequestMapping("/dictTypes")
  3. @Api(tags = "数据字典类型")
  4. public class DictTypeController {
  5. @Autowired
  6. private DictTypeService service;
  7. @GetMapping("/list")
  8. @ApiOperation(value = "返回所有的数据字典类型",notes = "可以传分页大小,第几页等")
  9. public Map<String,Object> listAll(DictTypeQuery query,@ApiParam("用户token") String token)
  10. {
  11. Map<String,Object> map = new HashMap<>();
  12. map.put("code",0);
  13. map.put("data",service.list());
  14. return map;
  15. }
  16. }

image.png
如果结果返回的是实体模型数据,结果也有注释。

  1. @RestController
  2. @RequestMapping("/dictTypes")
  3. @Api(tags = "数据字典类型")
  4. public class DictTypeController {
  5. @Autowired
  6. private DictTypeService service;
  7. @GetMapping("/list")
  8. @ApiOperation(value = "返回测试数据",notes = "哈哈")
  9. public DictTypeQuery listAll(DictTypeQuery query)
  10. {
  11. return new DictTypeQuery();
  12. }
  13. }

image.png
一个比较完整的示例

  1. import io.swagger.annotations.ApiOperation;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.core.env.Environment;
  6. import org.springframework.core.env.Profiles;
  7. import springfox.documentation.builders.ApiInfoBuilder;
  8. import springfox.documentation.builders.PathSelectors;
  9. import springfox.documentation.builders.RequestHandlerSelectors;
  10. import springfox.documentation.builders.RequestParameterBuilder;
  11. import springfox.documentation.service.ApiInfo;
  12. import springfox.documentation.service.Contact;
  13. import springfox.documentation.service.ParameterType;
  14. import springfox.documentation.service.RequestParameter;
  15. import springfox.documentation.spi.DocumentationType;
  16. import springfox.documentation.spring.web.plugins.Docket;
  17. import javax.servlet.http.HttpServletRequest;
  18. import javax.servlet.http.HttpServletResponse;
  19. import javax.servlet.http.HttpSession;
  20. import java.util.List;
  21. @Configuration
  22. public class SwaggerCfg {
  23. @Autowired
  24. private Environment environment;
  25. @Bean
  26. public Docket group1() {
  27. return groupDocket("/(正则表达式)",
  28. "分组1", "描述");
  29. }
  30. @Bean
  31. public Docket group2() {
  32. return groupDocket("/(正则表达式)",
  33. "分组2", "描述");
  34. }
  35. @Bean
  36. public Docket group3() {
  37. return groupDocket("/(正则表达式)",
  38. "分组3", "描述");
  39. }
  40. public Docket basicDocket() {
  41. //根据环境是否启用Swagger功能
  42. boolean enable = environment.acceptsProfiles(Profiles.of("dev", "test"));
  43. //设置全局参数
  44. RequestParameter tokenParam = new RequestParameterBuilder()
  45. .name("Token")
  46. .description("用户登录令牌")
  47. .in(ParameterType.HEADER)
  48. .build();
  49. return new Docket(DocumentationType.SWAGGER_2)
  50. //设置全局参数
  51. .globalRequestParameters(List.of(tokenParam))
  52. .enable(enable)
  53. .ignoredParameterTypes(
  54. HttpSession.class,
  55. HttpServletRequest.class,
  56. HttpServletResponse.class);
  57. }
  58. public Docket groupDocket(String regex, String title, String desc) {
  59. return basicDocket().groupName(title)
  60. .apiInfo(apiInfo(title, desc))
  61. .select()
  62. //根据是否有ApiOperation的方法,生成Swagger文档
  63. .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
  64. .paths(PathSelectors.regex(regex))
  65. .build();
  66. }
  67. private ApiInfo apiInfo(String title, String desc) {
  68. Contact contact = new Contact("作者:李付发","http://www.baidu.com","1966591729@qq.com");
  69. return new ApiInfoBuilder()
  70. .title(title)
  71. .version("1.0.0")
  72. .description(desc)
  73. .contact(contact)
  74. .build();
  75. }
  76. }

总结:非常优秀的接口调试工具。