8.Spring Boot 中使用 swagger

2020年01月19日 11:08 · 阅读(553) ·

Spring Boot

目标

在 Spring Boot 项目中使用 swagger 进行接口测试

开发环境

名称 版本
操作系统 Windows 10 X64
JDK JDK1.8(jdk-8u151-windows-x64)
IntelliJ IDEA IntelliJ IDEA 2018.3
Maven Maven 3.6.0
swagger2 2.7.0
swagger-ui 2.7.0

说明

本文代码基于 7.Spring Boot 中使用 Redis 数据库 的基础上进行修改

test-invoice-web

pom.xml

  1. <properties>
  2. <swagger.version>2.7.0</swagger.version>
  3. <swagger-ui.version>2.7.0</swagger-ui.version>
  4. </properties>
  5. <dependencies>
  6. <!--swagger start-->
  7. <!--springfox是通过注解的形式自动生成API文档,利用它,可以很方便的书写restful API,swagger主要用于展示springfox生成的API文档-->
  8. <dependency>
  9. <groupId>io.springfox</groupId>
  10. <artifactId>springfox-swagger2</artifactId>
  11. <version>${swagger.version}</version>
  12. </dependency>
  13. <dependency>
  14. <groupId>io.springfox</groupId>
  15. <artifactId>springfox-swagger-ui</artifactId>
  16. <version>${swagger-ui.version}</version>
  17. </dependency>
  18. <!--swagger end-->
  19. </dependencies>

application.yml

  1. # 是否显示swagger-ui
  2. swagger.show: true

Swagger 配置类-SwaggerConfig

  1. package com.test.invoice.config;
  2. import com.alibaba.fastjson.annotation.JSONField;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import com.fasterxml.jackson.databind.PropertyName;
  5. import com.fasterxml.jackson.databind.introspect.Annotated;
  6. import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
  7. import com.fasterxml.jackson.databind.module.SimpleModule;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.beans.factory.annotation.Value;
  10. import org.springframework.context.ApplicationContext;
  11. import org.springframework.context.annotation.Bean;
  12. import org.springframework.context.annotation.Configuration;
  13. import org.springframework.web.context.request.async.DeferredResult;
  14. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  15. import springfox.documentation.builders.ApiInfoBuilder;
  16. import springfox.documentation.builders.RequestHandlerSelectors;
  17. import springfox.documentation.schema.configuration.ObjectMapperConfigured;
  18. import springfox.documentation.service.ApiInfo;
  19. import springfox.documentation.spi.DocumentationType;
  20. import springfox.documentation.spring.web.plugins.Docket;
  21. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  22. import javax.annotation.PostConstruct;
  23. import java.lang.annotation.Annotation;
  24. /**
  25. * Swagger 配置类
  26. *
  27. * @author:
  28. * @date: 2020-01-17 16:26
  29. */
  30. @Configuration
  31. @EnableSwagger2
  32. public class SwaggerConfig extends WebMvcConfigurerAdapter {
  33. @Value("${swagger.show}")
  34. private boolean enableSwagger;
  35. @Autowired
  36. private ApplicationContext applicationContext;
  37. @PostConstruct
  38. public void setObjectMapper() {
  39. ObjectMapper objectMapper = new ObjectMapper();
  40. SimpleModule module = new SimpleModule();
  41. objectMapper.registerModule(module);
  42. JacksonAnnotationIntrospector jacksonAnnotationIntrospector= new JacksonAnnotationIntrospector();
  43. objectMapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
  44. @Override
  45. public boolean isAnnotationBundle(Annotation ann) {
  46. if (ann.annotationType() == JSONField.class) {
  47. return true;
  48. }
  49. return super.isAnnotationBundle(ann);
  50. }
  51. @Override
  52. public PropertyName findNameForSerialization(Annotated a) {
  53. PropertyName nameForSerialization = super.findNameForSerialization(a);
  54. if (nameForSerialization == null || nameForSerialization == PropertyName.USE_DEFAULT) {
  55. JSONField jsonField = _findAnnotation(a, JSONField.class);
  56. if (jsonField != null) {
  57. return PropertyName.construct(jsonField.name());
  58. }
  59. }
  60. return nameForSerialization;
  61. }
  62. @Override
  63. public PropertyName findNameForDeserialization(Annotated a) {
  64. PropertyName nameForDeserialization = super.findNameForDeserialization(a);
  65. if (nameForDeserialization == null || nameForDeserialization == PropertyName.USE_DEFAULT) {
  66. JSONField jsonField = _findAnnotation(a, JSONField.class);
  67. if (jsonField != null) {
  68. return PropertyName.construct(jsonField.name());
  69. }
  70. }
  71. return nameForDeserialization;
  72. }
  73. });
  74. ObjectMapperConfigured objectMapperConfigured = new ObjectMapperConfigured(applicationContext, objectMapper);
  75. applicationContext.publishEvent(objectMapperConfigured);
  76. }
  77. @Bean
  78. public Docket api() {
  79. return new Docket(DocumentationType.SWAGGER_2).groupName("framework").enable(enableSwagger)
  80. .genericModelSubstitutes(DeferredResult.class).useDefaultResponseMessages(false)
  81. .forCodeGeneration(false).pathMapping("/").apiInfo(apiInfo()).select()
  82. .apis(RequestHandlerSelectors.basePackage("com.test.invoice.control")).build();
  83. //com.test.invoice.controller
  84. //package com.foreign.payment.web.controller
  85. }
  86. private ApiInfo apiInfo() {
  87. return new ApiInfoBuilder().title("应用框架").description("平台接口文档").termsOfServiceUrl("")
  88. .contact("测试项目").version("1.0").build();
  89. }
  90. }

MVC 配置类-WebMVCConfig

  1. package com.test.invoice.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  4. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  5. /**
  6. * Created by on 2019/4/9.
  7. * 是因为swagger-ui.html 是在springfox-swagger-ui.jar里的,因为修改了路径Spring Boot不会自动把/swagger-ui.html这个路径映射到对应的目录META-INF/resources/下面。
  8. *所以我们修改springboot配置类,为swagger建立新的静态文件路径映射就可以了
  9. *原文:https://blog.csdn.net/weixin_39168678/article/details/80563402
  10. */
  11. @Configuration
  12. public class WebMVCConfig extends WebMvcConfigurerAdapter {
  13. @Override
  14. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  15. registry.addResourceHandler("swagger-ui.html")
  16. .addResourceLocations("classpath:/META-INF/resources/");
  17. registry.addResourceHandler("/webjars/**")
  18. .addResourceLocations("classpath:/META-INF/resources/webjars/");
  19. }
  20. }

测试类-TRbtTestController

  1. package com.test.invoice.controller;
  2. import com.alibaba.fastjson.JSON;
  3. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  4. import com.google.gson.Gson;
  5. import com.google.gson.GsonBuilder;
  6. import com.test.invoice.data.TRbtTestData;
  7. import com.test.invoice.data.TRbtTestDataParam;
  8. import com.test.invoice.enums.ResponseCode;
  9. import com.test.invoice.model.TRbtTestEntity;
  10. import com.test.invoice.model.TRbtUserEntity;
  11. import com.test.invoice.model.base.SuperEntity;
  12. import com.test.invoice.service.consumer.TRbtTestConsumer;
  13. import com.test.invoice.util.*;
  14. import com.test.invoice.vo.LoginRequestVO;
  15. import com.test.invoice.vo.ResponseVO;
  16. import io.swagger.annotations.Api;
  17. import io.swagger.annotations.ApiImplicitParam;
  18. import io.swagger.annotations.ApiImplicitParams;
  19. import io.swagger.annotations.ApiOperation;
  20. import lombok.extern.slf4j.Slf4j;
  21. import org.apache.commons.lang3.StringUtils;
  22. import org.springframework.web.bind.annotation.*;
  23. import org.springframework.beans.factory.annotation.Autowired;
  24. import javax.servlet.http.HttpServletRequest;
  25. import javax.ws.rs.POST;
  26. import java.net.URLEncoder;
  27. import java.time.LocalDate;
  28. import java.util.ArrayList;
  29. import java.util.HashMap;
  30. import java.util.List;
  31. import java.util.Map;
  32. /**
  33. * 消费者,通过 Feign-api 调用
  34. *
  35. * @author:
  36. * @version:
  37. * @date: 2019-08-12 14:49
  38. */
  39. @RestController
  40. @Api(description = "测试框架系统控制类")
  41. @RequestMapping("/Inv/Api")
  42. @Slf4j
  43. public class TRbtTestController {
  44. /**
  45. * ClassToJson
  46. * @param data TRbtTestData
  47. * @param convertType 1:使用 GSON 转换,2:使用 alibaba.fastjson 转换
  48. * @return JsonString
  49. */
  50. @PostMapping("/Test/ClassToJson")
  51. @ApiOperation(value = "类转 Json",httpMethod = "POST",response = ResponseVO.class,notes="类转 Json")
  52. public ResponseVO ClassToJson(@RequestBody TRbtTestData data,@RequestParam(value="convertType",required = true) String convertType)
  53. {
  54. ResponseVO responseVO = new ResponseVO<String>();
  55. if (convertType.equals("1")){
  56. GsonBuilder builder = new GsonBuilder();
  57. Gson gson = builder.create();
  58. responseVO.setData(gson.toJson(data));
  59. }else if (convertType.equals("2")){
  60. responseVO.setData(JSON.toJSONString(data));
  61. }
  62. responseVO.setCode(ResponseCode.OK.value());
  63. return responseVO;
  64. }
  65. /**
  66. * WebClientTest
  67. * @return String
  68. */
  69. @PostMapping("/Test/PinYin")
  70. @ApiImplicitParams({@ApiImplicitParam(paramType = "header", name = "Authorization", value = "凭证", required = true, dataType = "string"),})
  71. public ResponseVO PinYin(){
  72. ResponseVO responseVO = new ResponseVO<String>();
  73. CharacterPinYinConvert convert = new CharacterPinYinConvert();
  74. responseVO.setData(convert.toPinYin("罗马")+"======"+convert.toPinYins("一加一的和等于二"));
  75. return responseVO;
  76. }
  77. }

测试

浏览器访问 http://localhost:8080//swagger-ui.html

测试-ClassToJson

测试-PinYin

Spring Boot3-OpenAPI 3 与 Swagger

整合

  • 导入场景
  1. <dependency>
  2. <groupId>org.springdoc</groupId>
  3. <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
  4. <version>2.1.0</version>
  5. </dependency>
  • 配置
  1. # /api-docs endpoint custom path 默认 /v3/api-docs
  2. springdoc.api-docs.path=/api-docs
  3. # swagger 相关配置在 springdoc.swagger-ui
  4. # swagger-ui custom path
  5. springdoc.swagger-ui.path=/swagger-ui.html
  6. springdoc.show-actuator=true

使用

1.常用注解

注解 标注位置 作用
@Tag controller 类 标识 controller 作用
@Parameter 参数 标识参数作用
@Parameters 参数 参数多重说明
@Schema model 层的 JavaBean 描述模型作用及每个属性
@Operation 方法 描述方法作用
@ApiResponse 方法 描述响应状态码等

2.Docket配置

如果有多个 Docket,配置如下

  1. @Bean
  2. public GroupedOpenApi publicApi() {
  3. return GroupedOpenApi.builder()
  4. .group("springshop-public")
  5. .pathsToMatch("/public/**")
  6. .build();
  7. }
  8. @Bean
  9. public GroupedOpenApi adminApi() {
  10. return GroupedOpenApi.builder()
  11. .group("springshop-admin")
  12. .pathsToMatch("/admin/**")
  13. .addMethodFilter(method -> method.isAnnotationPresent(Admin.class))
  14. .build();
  15. }

如果只有一个 Docket,可以配置如下

  1. springdoc.packagesToScan=package1, package2
  2. springdoc.pathsToMatch=/v1, /api/balance/**

3.OpenAPI 配置

  1. @Bean
  2. public OpenAPI springShopOpenAPI() {
  3. return new OpenAPI()
  4. .info(new Info().title("SpringShop API")
  5. .description("Spring shop sample application")
  6. .version("v0.0.1")
  7. .license(new License().name("Apache 2.0").url("http://springdoc.org")))
  8. .externalDocs(new ExternalDocumentation()
  9. .description("SpringShop Wiki Documentation")
  10. .url("https://springshop.wiki.github.org/docs"));
  11. }

Springfox 迁移

1.注解变化

原注解 现注解 作用
@Api @Tag 描述 Controller
@ApiIgnore @Parameter(hidden = true)
@Operation(hidden = true)
@Hidden
描述忽略操作
@ApiImplicitParam @Parameter 描述参数
@ApiImplicitParams @Parameters 描述参数
@ApiModel @Schema 描述对象
@ApiModelProperty(hidden = true) @Schema(accessMode = READ_ONLY) 描述对象属性
@ApiModelProperty @Schema 描述对象属性
@ApiOperation(value = “foo”, notes = “bar”) @Operation(summary = “foo”, description = “bar”) 描述方法
@ApiParam @Parameter 描述参数
@ApiResponse(code = 404, message = “foo”) @ApiResponse(responseCode = “404”, description = “foo”) 描述响应

2.Docket 配置

(1)以前写法

  1. @Bean
  2. public Docket publicApi() {
  3. return new Docket(DocumentationType.SWAGGER_2)
  4. .select()
  5. .apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.public"))
  6. .paths(PathSelectors.regex("/public.*"))
  7. .build()
  8. .groupName("springshop-public")
  9. .apiInfo(apiInfo());
  10. }
  11. @Bean
  12. public Docket adminApi() {
  13. return new Docket(DocumentationType.SWAGGER_2)
  14. .select()
  15. .apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.admin"))
  16. .paths(PathSelectors.regex("/admin.*"))
  17. .apis(RequestHandlerSelectors.withMethodAnnotation(Admin.class))
  18. .build()
  19. .groupName("springshop-admin")
  20. .apiInfo(apiInfo());
  21. }

(2)新写法

  1. @Bean
  2. public GroupedOpenApi publicApi() {
  3. return GroupedOpenApi.builder()
  4. .group("springshop-public")
  5. .pathsToMatch("/public/**")
  6. .build();
  7. }
  8. @Bean
  9. public GroupedOpenApi adminApi() {
  10. return GroupedOpenApi.builder()
  11. .group("springshop-admin")
  12. .pathsToMatch("/admin/**")
  13. .addOpenApiMethodFilter(method -> method.isAnnotationPresent(Admin.class))
  14. .build();
  15. }

(3)添加 OpenAPI 组件

  1. @Bean
  2. public OpenAPI springShopOpenAPI() {
  3. return new OpenAPI()
  4. .info(new Info().title("SpringShop API")
  5. .description("Spring shop sample application")
  6. .version("v0.0.1")
  7. .license(new License().name("Apache 2.0").url("http://springdoc.org")))
  8. .externalDocs(new ExternalDocumentation()
  9. .description("SpringShop Wiki Documentation")
  10. .url("https://springshop.wiki.github.org/docs"));
  11. }