活动公告

系统通知
05-18 21:22
系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

Swagger2.0与Spring Boot 2.0完美整合 从零开始构建现代化API文档管理系统 提升开发效率与团队协作能力 快速实现接口自动化测试

SunJu_FaceMall

3万

主题

2860

科技点

3万

积分

白金月票

碾压王

积分
32872

塔罗立华奏

<font color=白金月票" /> 发表于 2025-9-9 19:30:13 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

在当今快速发展的软件开发领域,API(应用程序编程接口)已经成为不同系统之间通信的核心。随着微服务架构的普及,API的数量和复杂性也在不断增加,这使得API文档的管理和维护变得尤为重要。良好的API文档不仅可以帮助开发者理解和使用API,还能促进团队成员之间的协作,提高开发效率。

Swagger(现称为OpenAPI Specification)是一个强大且广泛使用的API文档规范和工具集,它可以帮助我们设计、构建、记录和使用RESTful Web服务。而Spring Boot作为Java生态系统中最受欢迎的框架之一,简化了Spring应用程序的创建和部署过程。

本文将详细介绍如何将Swagger2.0与Spring Boot 2.0完美整合,从零开始构建一个现代化的API文档管理系统,从而提升开发效率与团队协作能力,并快速实现接口自动化测试。

Swagger2.0简介

Swagger2.0是一个用于描述和记录RESTful API的规范和工具集。它允许开发者以一种标准化的方式定义API的结构,包括端点、参数、请求/响应模型等。Swagger2.0的核心组件包括:

1. Swagger Specification:一个JSON或YAML格式的API描述文件,定义了API的结构和行为。
2. Swagger UI:一个基于HTML的交互式API文档界面,允许开发者查看和测试API。
3. Swagger Editor:一个在线编辑器,用于编写和验证Swagger规范。
4. Swagger Codegen:一个代码生成工具,可以根据Swagger规范生成客户端SDK和服务器存根。

Swagger2.0的主要优势包括:

• 交互式API文档:提供可视化的API文档,开发者可以直接在浏览器中测试API端点。
• 标准化API描述:使用统一的格式描述API,便于理解和维护。
• 客户端代码生成:可以根据API描述自动生成客户端代码,减少重复工作。
• 自动化测试:结合其他工具,可以实现API的自动化测试。
• 团队协作:提供统一的API文档平台,促进团队成员之间的协作。

Spring Boot 2.0简介

Spring Boot 2.0是Spring框架的一个版本,它简化了Spring应用程序的创建和部署过程。Spring Boot 2.0引入了许多新特性和改进,包括:

1. 自动配置:根据项目依赖自动配置Spring应用程序,减少手动配置的需要。
2. 嵌入式服务器:内置Tomcat、Jetty或Undertow服务器,无需单独部署WAR文件。
3. 生产就绪特性:提供健康检查、指标收集和外部化配置等生产环境所需的功能。
4. Spring 5框架支持:基于Spring 5框架构建,支持响应式编程模型。
5. 改进的性能和内存使用:优化了性能和内存使用,适合构建微服务架构。
6. 对Java 9的支持:完全支持Java 9的新特性。

Spring Boot 2.0的主要优势包括:

• 简化开发:减少样板代码和配置,让开发者专注于业务逻辑。
• 快速启动:项目可以快速启动和运行,提高开发效率。
• 微服务友好:非常适合构建和部署微服务架构。
• 丰富的生态系统:与Spring生态系统中的其他项目无缝集成。
• 社区支持:拥有庞大的开发者社区和丰富的学习资源。

环境准备

在开始整合Swagger2.0和Spring Boot 2.0之前,我们需要准备开发环境。以下是所需的环境和工具:

1. Java Development Kit (JDK):安装JDK 8或更高版本。建议使用JDK 11,因为它是Spring Boot 2.0的长期支持版本。
  1. # 检查Java版本
  2.    java -version
复制代码

1. 集成开发环境 (IDE):推荐使用IntelliJ IDEA或Eclipse。这些IDE提供了强大的Spring Boot支持,可以简化开发过程。
2. 构建工具:Maven或Gradle。本文将使用Maven作为构建工具。
3. Spring Boot CLI(可选):可以用于快速创建和测试Spring Boot应用程序。
4. Postman(可选):用于测试API端点。
5. Git:用于版本控制。

集成开发环境 (IDE):推荐使用IntelliJ IDEA或Eclipse。这些IDE提供了强大的Spring Boot支持,可以简化开发过程。

构建工具:Maven或Gradle。本文将使用Maven作为构建工具。

Spring Boot CLI(可选):可以用于快速创建和测试Spring Boot应用程序。

Postman(可选):用于测试API端点。

Git:用于版本控制。

创建一个新的Spring Boot项目可以通过以下几种方式:

使用Spring Initializr网站

1. 访问https://start.spring.io/
2. 选择以下配置:Project: Maven ProjectLanguage: JavaSpring Boot: 2.7.x(或更高版本)Project Metadata:Group: com.exampleArtifact: swagger-spring-boot-demoName: swagger-spring-boot-demoDescription: Demo project for Spring Boot with SwaggerPackage Name: com.example.swaggerspringbootdemoDependencies: Spring Web
3. Project: Maven Project
4. Language: Java
5. Spring Boot: 2.7.x(或更高版本)
6. Project Metadata:Group: com.exampleArtifact: swagger-spring-boot-demoName: swagger-spring-boot-demoDescription: Demo project for Spring Boot with SwaggerPackage Name: com.example.swaggerspringbootdemo
7. Group: com.example
8. Artifact: swagger-spring-boot-demo
9. Name: swagger-spring-boot-demo
10. Description: Demo project for Spring Boot with Swagger
11. Package Name: com.example.swaggerspringbootdemo
12. Dependencies: Spring Web
13. 点击”Generate”按钮下载项目压缩包。
14. 解压压缩包,并在IDE中打开项目。

访问https://start.spring.io/

选择以下配置:

• Project: Maven Project
• Language: Java
• Spring Boot: 2.7.x(或更高版本)
• Project Metadata:Group: com.exampleArtifact: swagger-spring-boot-demoName: swagger-spring-boot-demoDescription: Demo project for Spring Boot with SwaggerPackage Name: com.example.swaggerspringbootdemo
• Group: com.example
• Artifact: swagger-spring-boot-demo
• Name: swagger-spring-boot-demo
• Description: Demo project for Spring Boot with Swagger
• Package Name: com.example.swaggerspringbootdemo
• Dependencies: Spring Web

• Group: com.example
• Artifact: swagger-spring-boot-demo
• Name: swagger-spring-boot-demo
• Description: Demo project for Spring Boot with Swagger
• Package Name: com.example.swaggerspringbootdemo

点击”Generate”按钮下载项目压缩包。

解压压缩包,并在IDE中打开项目。

使用Spring Boot CLI
  1. # 使用Spring Boot CLI创建项目
  2. spring init --dependencies=web swagger-spring-boot-demo
  3. cd swagger-spring-boot-demo
复制代码

整合步骤

现在,我们开始将Swagger2.0与Spring Boot 2.0整合。以下是详细的步骤和代码示例:

添加Swagger依赖

首先,我们需要在项目的pom.xml文件中添加Swagger2.0的依赖:
  1. <dependencies>
  2.     <!-- Spring Boot Web Starter -->
  3.     <dependency>
  4.         <groupId>org.springframework.boot</groupId>
  5.         <artifactId>spring-boot-starter-web</artifactId>
  6.     </dependency>
  7.    
  8.     <!-- Swagger2 -->
  9.     <dependency>
  10.         <groupId>io.springfox</groupId>
  11.         <artifactId>springfox-swagger2</artifactId>
  12.         <version>2.9.2</version>
  13.     </dependency>
  14.    
  15.     <!-- Swagger UI -->
  16.     <dependency>
  17.         <groupId>io.springfox</groupId>
  18.         <artifactId>springfox-swagger-ui</artifactId>
  19.         <version>2.9.2</version>
  20.     </dependency>
  21.    
  22.     <!-- Spring Boot Test -->
  23.     <dependency>
  24.         <groupId>org.springframework.boot</groupId>
  25.         <artifactId>spring-boot-starter-test</artifactId>
  26.         <scope>test</scope>
  27.     </dependency>
  28. </dependencies>
复制代码

在这里,我们添加了两个主要的Swagger依赖:

• springfox-swagger2:提供Swagger2的核心功能。
• springfox-swagger-ui:提供Swagger UI界面。

配置Swagger

接下来,我们需要创建一个配置类来启用Swagger:
  1. package com.example.swaggerspringbootdemo.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  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.service.Contact;
  9. import springfox.documentation.spi.DocumentationType;
  10. import springfox.documentation.spring.web.plugins.Docket;
  11. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  12. @Configuration
  13. @EnableSwagger2
  14. public class SwaggerConfig {
  15.     @Bean
  16.     public Docket api() {
  17.         return new Docket(DocumentationType.SWAGGER_2)
  18.                 .select()
  19.                 .apis(RequestHandlerSelectors.basePackage("com.example.swaggerspringbootdemo.controller"))
  20.                 .paths(PathSelectors.any())
  21.                 .build()
  22.                 .apiInfo(apiInfo());
  23.     }
  24.     private ApiInfo apiInfo() {
  25.         return new ApiInfoBuilder()
  26.                 .title("Spring Boot REST API with Swagger")
  27.                 .description("Spring Boot REST API with Swagger documentation")
  28.                 .version("1.0")
  29.                 .contact(new Contact("John Doe", "https://example.com", "john.doe@example.com"))
  30.                 .build();
  31.     }
  32. }
复制代码

在这个配置类中:

• @Configuration注解表示这是一个配置类。
• @EnableSwagger2注解启用Swagger2。
• DocketBean是Swagger的主要配置类,它定义了API文档的生成方式。
• apis()方法指定要扫描的控制器包。
• paths()方法指定要包含的路径模式。
• apiInfo()方法设置API的基本信息,如标题、描述和版本。

创建API控制器

现在,让我们创建一个简单的REST控制器,并使用Swagger注解来描述API:
  1. package com.example.swaggerspringbootdemo.controller;
  2. import io.swagger.annotations.Api;
  3. import io.swagger.annotations.ApiOperation;
  4. import io.swagger.annotations.ApiParam;
  5. import io.swagger.annotations.ApiResponse;
  6. import io.swagger.annotations.ApiResponses;
  7. import org.springframework.http.HttpStatus;
  8. import org.springframework.http.ResponseEntity;
  9. import org.springframework.web.bind.annotation.*;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12. import java.util.concurrent.ConcurrentHashMap;
  13. import java.util.concurrent.atomic.AtomicLong;
  14. @Api(value = "User Management System", description = "Operations pertaining to user in User Management System")
  15. @RestController
  16. @RequestMapping("/api/users")
  17. public class UserController {
  18.     private final ConcurrentHashMap<Long, User> userMap = new ConcurrentHashMap<>();
  19.     private final AtomicLong counter = new AtomicLong(1);
  20.     @ApiOperation(value = "View a list of available users", response = List.class)
  21.     @ApiResponses(value = {
  22.             @ApiResponse(code = 200, message = "Successfully retrieved list"),
  23.             @ApiResponse(code = 401, message = "You are not authorized to view the resource"),
  24.             @ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"),
  25.             @ApiResponse(code = 404, message = "The resource you were trying to reach is not found")
  26.     })
  27.     @GetMapping
  28.     public ResponseEntity<List<User>> getAllUsers() {
  29.         return new ResponseEntity<>(new ArrayList<>(userMap.values()), HttpStatus.OK);
  30.     }
  31.     @ApiOperation(value = "Get a user by Id", response = User.class)
  32.     @GetMapping("/{id}")
  33.     public ResponseEntity<User> getUserById(
  34.             @ApiParam(value = "User id from which user object will retrieve", required = true) @PathVariable Long id) {
  35.         User user = userMap.get(id);
  36.         if (user == null) {
  37.             return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  38.         }
  39.         return new ResponseEntity<>(user, HttpStatus.OK);
  40.     }
  41.     @ApiOperation(value = "Add a user")
  42.     @PostMapping
  43.     public ResponseEntity<User> createUser(
  44.             @ApiParam(value = "User object store in database table", required = true) @RequestBody User user) {
  45.         long id = counter.getAndIncrement();
  46.         user.setId(id);
  47.         userMap.put(id, user);
  48.         return new ResponseEntity<>(user, HttpStatus.CREATED);
  49.     }
  50.     @ApiOperation(value = "Update a user")
  51.     @PutMapping("/{id}")
  52.     public ResponseEntity<User> updateUser(
  53.             @ApiParam(value = "User Id to update user object", required = true) @PathVariable Long id,
  54.             @ApiParam(value = "Update user object", required = true) @RequestBody User user) {
  55.         if (!userMap.containsKey(id)) {
  56.             return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  57.         }
  58.         user.setId(id);
  59.         userMap.put(id, user);
  60.         return new ResponseEntity<>(user, HttpStatus.OK);
  61.     }
  62.     @ApiOperation(value = "Delete a user")
  63.     @DeleteMapping("/{id}")
  64.     public ResponseEntity<Void> deleteUser(
  65.             @ApiParam(value = "User Id from which user object will delete from database table", required = true) @PathVariable Long id) {
  66.         if (!userMap.containsKey(id)) {
  67.             return new ResponseEntity<>(HttpStatus.NOT_FOUND);
  68.         }
  69.         userMap.remove(id);
  70.         return new ResponseEntity<>(HttpStatus.NO_CONTENT);
  71.     }
  72. }
复制代码

在这个控制器中,我们使用了多个Swagger注解:

• @Api:用于描述控制器类。
• @ApiOperation:用于描述方法的功能。
• @ApiParam:用于描述参数。
• @ApiResponses和@ApiResponse:用于描述可能的响应。

创建模型类

接下来,创建一个User模型类:
  1. package com.example.swaggerspringbootdemo.controller;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. @ApiModel(description = "User details")
  5. public class User {
  6.     @ApiModelProperty(notes = "The database generated user ID")
  7.     private Long id;
  8.    
  9.     @ApiModelProperty(notes = "The user's first name", required = true)
  10.     private String firstName;
  11.    
  12.     @ApiModelProperty(notes = "The user's last name", required = true)
  13.     private String lastName;
  14.    
  15.     @ApiModelProperty(notes = "The user's email address", required = true)
  16.     private String email;
  17.     // Constructors, getters, and setters
  18.     public User() {
  19.     }
  20.     public User(String firstName, String lastName, String email) {
  21.         this.firstName = firstName;
  22.         this.lastName = lastName;
  23.         this.email = email;
  24.     }
  25.     public Long getId() {
  26.         return id;
  27.     }
  28.     public void setId(Long id) {
  29.         this.id = id;
  30.     }
  31.     public String getFirstName() {
  32.         return firstName;
  33.     }
  34.     public void setFirstName(String firstName) {
  35.         this.firstName = firstName;
  36.     }
  37.     public String getLastName() {
  38.         return lastName;
  39.     }
  40.     public void setLastName(String lastName) {
  41.         this.lastName = lastName;
  42.     }
  43.     public String getEmail() {
  44.         return email;
  45.     }
  46.     public void setEmail(String email) {
  47.         this.email = email;
  48.     }
  49. }
复制代码

在这个模型类中,我们使用了以下Swagger注解:

• @ApiModel:用于描述模型类。
• @ApiModelProperty:用于描述模型属性。

运行应用程序

现在,我们可以运行Spring Boot应用程序:
  1. package com.example.swaggerspringbootdemo;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class SwaggerSpringBootDemoApplication {
  6.     public static void main(String[] args) {
  7.         SpringApplication.run(SwaggerSpringBootDemoApplication.class, args);
  8.     }
  9. }
复制代码

启动应用程序后,访问http://localhost:8080/swagger-ui.html即可看到Swagger UI界面。在这个界面中,你可以查看所有API端点的文档,并进行测试。

高级功能

分组API

在大型项目中,我们可能需要对API进行分组,以便更好地组织和管理。Swagger支持通过多个Docket Bean来实现API分组:
  1. package com.example.swaggerspringbootdemo.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  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.service.Contact;
  9. import springfox.documentation.spi.DocumentationType;
  10. import springfox.documentation.spring.web.plugins.Docket;
  11. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  12. @Configuration
  13. @EnableSwagger2
  14. public class SwaggerConfig {
  15.     @Bean
  16.     public Docket publicApi() {
  17.         return new Docket(DocumentationType.SWAGGER_2)
  18.                 .groupName("public")
  19.                 .select()
  20.                 .apis(RequestHandlerSelectors.basePackage("com.example.swaggerspringbootdemo.controller.public"))
  21.                 .paths(PathSelectors.any())
  22.                 .build()
  23.                 .apiInfo(publicApiInfo());
  24.     }
  25.     @Bean
  26.     public Docket privateApi() {
  27.         return new Docket(DocumentationType.SWAGGER_2)
  28.                 .groupName("private")
  29.                 .select()
  30.                 .apis(RequestHandlerSelectors.basePackage("com.example.swaggerspringbootdemo.controller.private"))
  31.                 .paths(PathSelectors.any())
  32.                 .build()
  33.                 .apiInfo(privateApiInfo());
  34.     }
  35.     private ApiInfo publicApiInfo() {
  36.         return new ApiInfoBuilder()
  37.                 .title("Public API Documentation")
  38.                 .description("This is the documentation for public APIs")
  39.                 .version("1.0")
  40.                 .contact(new Contact("John Doe", "https://example.com", "john.doe@example.com"))
  41.                 .build();
  42.     }
  43.     private ApiInfo privateApiInfo() {
  44.         return new ApiInfoBuilder()
  45.                 .title("Private API Documentation")
  46.                 .description("This is the documentation for private APIs")
  47.                 .version("1.0")
  48.                 .contact(new Contact("John Doe", "https://example.com", "john.doe@example.com"))
  49.                 .build();
  50.     }
  51. }
复制代码

在这个配置中,我们创建了两个Docket Bean,分别对应公共API和私有API。每个Docket Bean都有自己的groupName,用于区分不同的API组。

自定义Swagger UI

Swagger UI可以通过自定义配置来满足不同的需求。我们可以创建一个自定义的Swagger UI配置:
  1. package com.example.swaggerspringbootdemo.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import springfox.documentation.swagger.web.UiConfiguration;
  4. import springfox.documentation.swagger.web.UiConfigurationBuilder;
  5. @Configuration
  6. public class SwaggerUiConfig {
  7.     @Bean
  8.     public UiConfiguration uiConfiguration() {
  9.         return UiConfigurationBuilder.builder()
  10.                 .displayRequestDuration(true)
  11.                 .docExpansion("none")
  12.                 .filter(true)
  13.                 .showExtensions(true)
  14.                 .build();
  15.     }
  16. }
复制代码

在这个配置中,我们:

• 启用了请求持续时间显示。
• 设置了文档展开方式为”none”。
• 启用了过滤器。
• 启用了扩展显示。

安全配置

在实际应用中,我们可能需要保护API文档,只允许授权用户访问。我们可以通过Spring Security来实现:

首先,添加Spring Security依赖:
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-security</artifactId>
  4. </dependency>
复制代码

然后,创建安全配置:
  1. package com.example.swaggerspringbootdemo.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  4. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  5. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  6. @Configuration
  7. @EnableWebSecurity
  8. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  9.     @Override
  10.     protected void configure(HttpSecurity http) throws Exception {
  11.         http
  12.             .authorizeRequests()
  13.                 .antMatchers("/swagger-ui.html").authenticated()
  14.                 .antMatchers("/swagger-resources/**").authenticated()
  15.                 .antMatchers("/v2/api-docs").authenticated()
  16.                 .antMatchers("/webjars/**").authenticated()
  17.                 .anyRequest().permitAll()
  18.             .and()
  19.             .formLogin()
  20.             .and()
  21.             .httpBasic();
  22.     }
  23. }
复制代码

在这个配置中,我们要求访问Swagger UI和相关资源时必须进行身份验证,而其他API端点则允许所有人访问。

全局参数配置

在某些情况下,我们可能需要为所有API添加一些全局参数,例如认证令牌。这可以通过Docket配置来实现:
  1. package com.example.swaggerspringbootdemo.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import springfox.documentation.builders.ApiInfoBuilder;
  5. import springfox.documentation.builders.ParameterBuilder;
  6. import springfox.documentation.builders.PathSelectors;
  7. import springfox.documentation.builders.RequestHandlerSelectors;
  8. import springfox.documentation.schema.ModelRef;
  9. import springfox.documentation.service.ApiInfo;
  10. import springfox.documentation.service.Contact;
  11. import springfox.documentation.service.Parameter;
  12. import springfox.documentation.spi.DocumentationType;
  13. import springfox.documentation.spring.web.plugins.Docket;
  14. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  15. import java.util.ArrayList;
  16. import java.util.List;
  17. @Configuration
  18. @EnableSwagger2
  19. public class SwaggerConfig {
  20.     @Bean
  21.     public Docket api() {
  22.         // 添加全局参数
  23.         ParameterBuilder parameterBuilder = new ParameterBuilder();
  24.         List<Parameter> parameters = new ArrayList<>();
  25.         parameterBuilder.name("Authorization")
  26.                 .description("Authorization token")
  27.                 .modelRef(new ModelRef("string"))
  28.                 .parameterType("header")
  29.                 .required(false)
  30.                 .build();
  31.         parameters.add(parameterBuilder.build());
  32.         return new Docket(DocumentationType.SWAGGER_2)
  33.                 .select()
  34.                 .apis(RequestHandlerSelectors.basePackage("com.example.swaggerspringbootdemo.controller"))
  35.                 .paths(PathSelectors.any())
  36.                 .build()
  37.                 .globalOperationParameters(parameters)
  38.                 .apiInfo(apiInfo());
  39.     }
  40.     private ApiInfo apiInfo() {
  41.         return new ApiInfoBuilder()
  42.                 .title("Spring Boot REST API with Swagger")
  43.                 .description("Spring Boot REST API with Swagger documentation")
  44.                 .version("1.0")
  45.                 .contact(new Contact("John Doe", "https://example.com", "john.doe@example.com"))
  46.                 .build();
  47.     }
  48. }
复制代码

在这个配置中,我们添加了一个名为”Authorization”的全局参数,它将出现在所有API端点中。

接口自动化测试

Swagger UI不仅提供了API文档,还可以用于接口测试。在Swagger UI界面中,每个API端点都有一个”Try it out”按钮,点击后可以输入参数并执行API请求,查看响应结果。

然而,对于更复杂的测试场景,我们可以结合其他工具来实现自动化测试。以下是一些常用的方法:

使用Swagger Codegen生成测试代码

Swagger Codegen可以根据Swagger规范生成客户端代码,包括测试代码。以下是使用Swagger Codegen生成测试代码的步骤:

1. 首先,确保已经安装了Swagger Codegen。可以从https://github.com/swagger-api/swagger-codegen下载。
2. 使用以下命令生成测试代码:

首先,确保已经安装了Swagger Codegen。可以从https://github.com/swagger-api/swagger-codegen下载。

使用以下命令生成测试代码:
  1. java -jar swagger-codegen-cli.jar generate \
  2.   -i http://localhost:8080/v2/api-docs \
  3.   -l java \
  4.   -o ./generated-code \
  5.   --library resttemplate \
  6.   --api-package com.example.client.api \
  7.   --model-package com.example.client.model \
  8.   --invoker-package com.example.client.invoker \
  9.   --group-id com.example \
  10.   --artifact-id swagger-java-client \
  11.   --artifact-version 1.0.0
复制代码

这个命令会根据提供的API文档生成Java客户端代码。

使用Spring Boot Test进行测试

Spring Boot Test提供了强大的测试支持,可以结合Swagger进行API测试:
  1. package com.example.swaggerspringbootdemo;
  2. import com.example.swaggerspringbootdemo.controller.User;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import org.junit.jupiter.api.Test;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
  7. import org.springframework.boot.test.context.SpringBootTest;
  8. import org.springframework.http.MediaType;
  9. import org.springframework.test.web.servlet.MockMvc;
  10. import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
  11. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
  12. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  13. @SpringBootTest
  14. @AutoConfigureMockMvc
  15. public class UserControllerTest {
  16.     @Autowired
  17.     private MockMvc mockMvc;
  18.     @Autowired
  19.     private ObjectMapper objectMapper;
  20.     @Test
  21.     public void testCreateUser() throws Exception {
  22.         User user = new User("John", "Doe", "john.doe@example.com");
  23.         mockMvc.perform(MockMvcRequestBuilders.post("/api/users")
  24.                 .contentType(MediaType.APPLICATION_JSON)
  25.                 .content(objectMapper.writeValueAsString(user)))
  26.                 .andExpect(status().isCreated())
  27.                 .andExpect(jsonPath("$.firstName").value("John"))
  28.                 .andExpect(jsonPath("$.lastName").value("Doe"))
  29.                 .andExpect(jsonPath("$.email").value("john.doe@example.com"));
  30.     }
  31.     @Test
  32.     public void testGetUserById() throws Exception {
  33.         // First, create a user
  34.         User user = new User("Jane", "Doe", "jane.doe@example.com");
  35.         String response = mockMvc.perform(MockMvcRequestBuilders.post("/api/users")
  36.                 .contentType(MediaType.APPLICATION_JSON)
  37.                 .content(objectMapper.writeValueAsString(user)))
  38.                 .andReturn().getResponse().getContentAsString();
  39.         // Extract the user ID from the response
  40.         Long userId = objectMapper.readTree(response).get("id").asLong();
  41.         // Then, get the user by ID
  42.         mockMvc.perform(MockMvcRequestBuilders.get("/api/users/{id}", userId))
  43.                 .andExpect(status().isOk())
  44.                 .andExpect(jsonPath("$.firstName").value("Jane"))
  45.                 .andExpect(jsonPath("$.lastName").value("Doe"))
  46.                 .andExpect(jsonPath("$.email").value("jane.doe@example.com"));
  47.     }
  48.     @Test
  49.     public void testUpdateUser() throws Exception {
  50.         // First, create a user
  51.         User user = new User("Bob", "Smith", "bob.smith@example.com");
  52.         String response = mockMvc.perform(MockMvcRequestBuilders.post("/api/users")
  53.                 .contentType(MediaType.APPLICATION_JSON)
  54.                 .content(objectMapper.writeValueAsString(user)))
  55.                 .andReturn().getResponse().getContentAsString();
  56.         // Extract the user ID from the response
  57.         Long userId = objectMapper.readTree(response).get("id").asLong();
  58.         // Update the user
  59.         User updatedUser = new User("Bob", "Johnson", "bob.johnson@example.com");
  60.         mockMvc.perform(MockMvcRequestBuilders.put("/api/users/{id}", userId)
  61.                 .contentType(MediaType.APPLICATION_JSON)
  62.                 .content(objectMapper.writeValueAsString(updatedUser)))
  63.                 .andExpect(status().isOk())
  64.                 .andExpect(jsonPath("$.firstName").value("Bob"))
  65.                 .andExpect(jsonPath("$.lastName").value("Johnson"))
  66.                 .andExpect(jsonPath("$.email").value("bob.johnson@example.com"));
  67.     }
  68.     @Test
  69.     public void testDeleteUser() throws Exception {
  70.         // First, create a user
  71.         User user = new User("Alice", "Williams", "alice.williams@example.com");
  72.         String response = mockMvc.perform(MockMvcRequestBuilders.post("/api/users")
  73.                 .contentType(MediaType.APPLICATION_JSON)
  74.                 .content(objectMapper.writeValueAsString(user)))
  75.                 .andReturn().getResponse().getContentAsString();
  76.         // Extract the user ID from the response
  77.         Long userId = objectMapper.readTree(response).get("id").asLong();
  78.         // Then, delete the user
  79.         mockMvc.perform(MockMvcRequestBuilders.delete("/api/users/{id}", userId))
  80.                 .andExpect(status().isNoContent());
  81.         // Verify that the user has been deleted
  82.         mockMvc.perform(MockMvcRequestBuilders.get("/api/users/{id}", userId))
  83.                 .andExpect(status().isNotFound());
  84.     }
  85. }
复制代码

在这个测试类中,我们使用了Spring Boot Test的MockMvc来测试API端点。每个测试方法都测试了一个特定的API操作,包括创建、获取、更新和删除用户。

使用Postman进行自动化测试

Postman是一个流行的API测试工具,可以与Swagger集成,实现自动化测试:

1. 从Swagger UI导出API规范:访问http://localhost:8080/v2/api-docs将JSON响应保存为文件
2. 访问http://localhost:8080/v2/api-docs
3. 将JSON响应保存为文件
4. 在Postman中导入API规范:打开Postman点击”Import”按钮选择保存的JSON文件
5. 打开Postman
6. 点击”Import”按钮
7. 选择保存的JSON文件
8. 创建测试集合:在Postman中,选择导入的API为每个端点创建测试请求添加测试脚本,例如:
9. 在Postman中,选择导入的API
10. 为每个端点创建测试请求
11. 添加测试脚本,例如:

从Swagger UI导出API规范:

• 访问http://localhost:8080/v2/api-docs
• 将JSON响应保存为文件

在Postman中导入API规范:

• 打开Postman
• 点击”Import”按钮
• 选择保存的JSON文件

创建测试集合:

• 在Postman中,选择导入的API
• 为每个端点创建测试请求
• 添加测试脚本,例如:
  1. pm.test("Status code is 200", function () {
  2.     pm.response.to.have.status(200);
  3. });
  4. pm.test("Response has user data", function () {
  5.     var jsonData = pm.response.json();
  6.     pm.expect(jsonData).to.have.property('firstName');
  7.     pm.expect(jsonData).to.have.property('lastName');
  8.     pm.expect(jsonData).to.have.property('email');
  9. });
复制代码

1. 运行测试集合:点击”Runner”按钮选择要运行的测试集合配置运行参数点击”Run”按钮执行测试
2. 点击”Runner”按钮
3. 选择要运行的测试集合
4. 配置运行参数
5. 点击”Run”按钮执行测试

• 点击”Runner”按钮
• 选择要运行的测试集合
• 配置运行参数
• 点击”Run”按钮执行测试

使用REST Assured进行测试

REST Assured是一个Java库,专门用于测试RESTful API。它可以与Spring Boot测试框架结合使用:

首先,添加REST Assured依赖:
  1. <dependency>
  2.     <groupId>io.rest-assured</groupId>
  3.     <artifactId>rest-assured</artifactId>
  4.     <version>4.3.3</version>
  5.     <scope>test</scope>
  6. </dependency>
复制代码

然后,创建测试类:
  1. package com.example.swaggerspringbootdemo;
  2. import com.example.swaggerspringbootdemo.controller.User;
  3. import io.restassured.http.ContentType;
  4. import org.junit.jupiter.api.BeforeEach;
  5. import org.junit.jupiter.api.Test;
  6. import org.springframework.boot.test.context.SpringBootTest;
  7. import org.springframework.boot.web.server.LocalServerPort;
  8. import static io.restassured.RestAssured.*;
  9. import static org.hamcrest.Matchers.*;
  10. @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  11. public class UserControllerRestAssuredTest {
  12.     @LocalServerPort
  13.     private int port;
  14.     @BeforeEach
  15.     public void setUp() {
  16.         baseURI = "http://localhost";
  17.         port = this.port;
  18.     }
  19.     @Test
  20.     public void testCreateUser() {
  21.         User user = new User("John", "Doe", "john.doe@example.com");
  22.         given()
  23.                 .contentType(ContentType.JSON)
  24.                 .body(user)
  25.                 .when()
  26.                 .post("/api/users")
  27.                 .then()
  28.                 .statusCode(201)
  29.                 .body("firstName", equalTo("John"))
  30.                 .body("lastName", equalTo("Doe"))
  31.                 .body("email", equalTo("john.doe@example.com"));
  32.     }
  33.     @Test
  34.     public void testGetUserById() {
  35.         // First, create a user
  36.         User user = new User("Jane", "Doe", "jane.doe@example.com");
  37.         Long userId = given()
  38.                 .contentType(ContentType.JSON)
  39.                 .body(user)
  40.                 .when()
  41.                 .post("/api/users")
  42.                 .then()
  43.                 .extract()
  44.                 .path("id");
  45.         // Then, get the user by ID
  46.         given()
  47.                 .when()
  48.                 .get("/api/users/{id}", userId)
  49.                 .then()
  50.                 .statusCode(200)
  51.                 .body("firstName", equalTo("Jane"))
  52.                 .body("lastName", equalTo("Doe"))
  53.                 .body("email", equalTo("jane.doe@example.com"));
  54.     }
  55.     @Test
  56.     public void testUpdateUser() {
  57.         // First, create a user
  58.         User user = new User("Bob", "Smith", "bob.smith@example.com");
  59.         Long userId = given()
  60.                 .contentType(ContentType.JSON)
  61.                 .body(user)
  62.                 .when()
  63.                 .post("/api/users")
  64.                 .then()
  65.                 .extract()
  66.                 .path("id");
  67.         // Update the user
  68.         User updatedUser = new User("Bob", "Johnson", "bob.johnson@example.com");
  69.         given()
  70.                 .contentType(ContentType.JSON)
  71.                 .body(updatedUser)
  72.                 .when()
  73.                 .put("/api/users/{id}", userId)
  74.                 .then()
  75.                 .statusCode(200)
  76.                 .body("firstName", equalTo("Bob"))
  77.                 .body("lastName", equalTo("Johnson"))
  78.                 .body("email", equalTo("bob.johnson@example.com"));
  79.     }
  80.     @Test
  81.     public void testDeleteUser() {
  82.         // First, create a user
  83.         User user = new User("Alice", "Williams", "alice.williams@example.com");
  84.         Long userId = given()
  85.                 .contentType(ContentType.JSON)
  86.                 .body(user)
  87.                 .when()
  88.                 .post("/api/users")
  89.                 .then()
  90.                 .extract()
  91.                 .path("id");
  92.         // Then, delete the user
  93.         given()
  94.                 .when()
  95.                 .delete("/api/users/{id}", userId)
  96.                 .then()
  97.                 .statusCode(204);
  98.         // Verify that the user has been deleted
  99.         given()
  100.                 .when()
  101.                 .get("/api/users/{id}", userId)
  102.                 .then()
  103.                 .statusCode(404);
  104.     }
  105. }
复制代码

在这个测试类中,我们使用REST Assured的流畅API来测试REST端点。每个测试方法都测试了一个特定的API操作,并验证了响应状态码和内容。

最佳实践

在使用Swagger2.0和Spring Boot 2.0构建API文档管理系统时,以下是一些最佳实践:

1. 保持API文档的更新

API文档应该与代码保持同步。为了实现这一点,可以:

• 在代码中使用Swagger注解,而不是单独维护文档。
• 在CI/CD流程中添加验证步骤,确保API文档与实际代码一致。
• 定期审查API文档,确保其准确性和完整性。

2. 使用语义化的HTTP状态码

使用适当的HTTP状态码可以帮助API消费者更好地理解API的响应:

• 200 OK:请求成功。
• 201 Created:资源创建成功。
• 204 No Content:请求成功,但没有返回内容。
• 400 Bad Request:客户端请求错误。
• 401 Unauthorized:需要身份验证。
• 403 Forbidden:服务器拒绝请求。
• 404 Not Found:请求的资源不存在。
• 500 Internal Server Error:服务器内部错误。

3. 提供详细的错误信息

当API返回错误时,提供详细的错误信息可以帮助开发者快速定位问题:
  1. @ApiOperation(value = "Get a user by Id", response = User.class)
  2. @ApiResponses(value = {
  3.         @ApiResponse(code = 200, message = "Successfully retrieved user"),
  4.         @ApiResponse(code = 404, message = "User not found with the provided ID")
  5. })
  6. @GetMapping("/{id}")
  7. public ResponseEntity<?> getUserById(
  8.         @ApiParam(value = "User id from which user object will retrieve", required = true) @PathVariable Long id) {
  9.     User user = userMap.get(id);
  10.     if (user == null) {
  11.         return ResponseEntity.status(HttpStatus.NOT_FOUND)
  12.                 .body(new ErrorResponse("User not found", "User with ID " + id + " does not exist"));
  13.     }
  14.     return ResponseEntity.ok(user);
  15. }
复制代码

4. 使用版本控制

API版本控制可以帮助管理API的变化,避免破坏现有客户端:
  1. @Api(value = "User Management System v1", description = "Operations pertaining to user in User Management System v1")
  2. @RestController
  3. @RequestMapping("/api/v1/users")
  4. public class UserControllerV1 {
  5.     // Controller implementation
  6. }
  7. @Api(value = "User Management System v2", description = "Operations pertaining to user in User Management System v2")
  8. @RestController
  9. @RequestMapping("/api/v2/users")
  10. public class UserControllerV2 {
  11.     // Controller implementation
  12. }
复制代码

5. 使用API分组

对于大型项目,使用API分组可以帮助组织和管理API:
  1. @Bean
  2. public Docket publicApi() {
  3.     return new Docket(DocumentationType.SWAGGER_2)
  4.             .groupName("public")
  5.             .select()
  6.             .apis(RequestHandlerSelectors.basePackage("com.example.swaggerspringbootdemo.controller.public"))
  7.             .paths(PathSelectors.any())
  8.             .build()
  9.             .apiInfo(publicApiInfo());
  10. }
  11. @Bean
  12. public Docket privateApi() {
  13.     return new Docket(DocumentationType.SWAGGER_2)
  14.             .groupName("private")
  15.             .select()
  16.             .apis(RequestHandlerSelectors.basePackage("com.example.swaggerspringbootdemo.controller.private"))
  17.             .paths(PathSelectors.any())
  18.             .build()
  19.             .apiInfo(privateApiInfo());
  20. }
复制代码

6. 添加安全配置

保护API文档和API端点,防止未授权访问:
  1. @Override
  2. protected void configure(HttpSecurity http) throws Exception {
  3.     http
  4.         .authorizeRequests()
  5.             .antMatchers("/swagger-ui.html").hasRole("DEVELOPER")
  6.             .antMatchers("/swagger-resources/**").hasRole("DEVELOPER")
  7.             .antMatchers("/v2/api-docs").hasRole("DEVELOPER")
  8.             .antMatchers("/webjars/**").hasRole("DEVELOPER")
  9.             .antMatchers("/api/public/**").permitAll()
  10.             .antMatchers("/api/private/**").hasRole("USER")
  11.             .anyRequest().authenticated()
  12.         .and()
  13.         .formLogin()
  14.         .and()
  15.         .httpBasic();
  16. }
复制代码

7. 使用注解提供详细的文档

使用Swagger注解提供详细的API文档:
  1. @ApiOperation(value = "Create a new user", notes = "Creates a new user with the provided details. The email address must be unique.")
  2. @ApiResponses(value = {
  3.         @ApiResponse(code = 201, message = "User created successfully", response = User.class),
  4.         @ApiResponse(code = 400, message = "Invalid input", response = ErrorResponse.class),
  5.         @ApiResponse(code = 409, message = "Email address already in use", response = ErrorResponse.class)
  6. })
  7. @PostMapping
  8. public ResponseEntity<?> createUser(
  9.         @ApiParam(value = "User details", required = true) @Valid @RequestBody UserDto userDto) {
  10.     // Implementation
  11. }
复制代码

8. 使用DTO进行数据传输

使用DTO(Data Transfer Object)进行数据传输,而不是直接暴露实体类:
  1. @ApiModel(description = "User data transfer object")
  2. public class UserDto {
  3.     @ApiModelProperty(notes = "The user's first name", required = true)
  4.     @NotBlank
  5.     private String firstName;
  6.    
  7.     @ApiModelProperty(notes = "The user's last name", required = true)
  8.     @NotBlank
  9.     private String lastName;
  10.    
  11.     @ApiModelProperty(notes = "The user's email address", required = true)
  12.     @Email
  13.     @NotBlank
  14.     private String email;
  15.    
  16.     // Getters and setters
  17. }
复制代码

9. 实现自动化测试

实现API的自动化测试,确保API的功能和性能:
  1. @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  2. @AutoConfigureMockMvc
  3. public class UserControllerTest {
  4.     @Autowired
  5.     private MockMvc mockMvc;
  6.     @Autowired
  7.     private ObjectMapper objectMapper;
  8.     @Test
  9.     public void testCreateUser() throws Exception {
  10.         UserDto userDto = new UserDto("John", "Doe", "john.doe@example.com");
  11.         mockMvc.perform(post("/api/users")
  12.                 .contentType(MediaType.APPLICATION_JSON)
  13.                 .content(objectMapper.writeValueAsString(userDto)))
  14.                 .andExpect(status().isCreated())
  15.                 .andExpect(jsonPath("$.firstName").value("John"))
  16.                 .andExpect(jsonPath("$.lastName").value("Doe"))
  17.                 .andExpect(jsonPath("$.email").value("john.doe@example.com"));
  18.     }
  19. }
复制代码

10. 集成到CI/CD流程

将API文档生成和测试集成到CI/CD流程中,确保代码变更不会破坏API:
  1. # .gitlab-ci.yml example
  2. stages:
  3.   - build
  4.   - test
  5.   - deploy
  6. build:
  7.   stage: build
  8.   script:
  9.     - ./mvnw clean compile
  10. test:
  11.   stage: test
  12.   script:
  13.     - ./mvnw test
  14.     - ./mvnw swagger2markup:convertSwagger2markup
  15. deploy:
  16.   stage: deploy
  17.   script:
  18.     - ./mvnw deploy
  19.   only:
  20.     - master
复制代码

总结

Swagger2.0与Spring Boot 2.0的整合为API开发和管理带来了许多好处。通过本文的介绍,我们了解了如何从零开始构建一个现代化的API文档管理系统,提升开发效率与团队协作能力,并快速实现接口自动化测试。

主要内容包括:

1. 环境准备:介绍了所需的开发环境和工具,以及如何创建Spring Boot项目。
2. 整合步骤:详细介绍了如何添加Swagger依赖、配置Swagger、创建API控制器和模型类。
3. 高级功能:介绍了API分组、自定义Swagger UI、安全配置和全局参数配置等高级功能。
4. 接口自动化测试:介绍了如何使用Swagger Codegen、Spring Boot Test、Postman和REST Assured进行API测试。
5. 最佳实践:提供了一些在使用Swagger2.0和Spring Boot 2.0构建API文档管理系统时的最佳实践。

通过整合Swagger2.0和Spring Boot 2.0,我们可以:

• 提高开发效率:自动生成API文档,减少手动编写文档的工作量。
• 增强团队协作:提供统一的API文档平台,促进团队成员之间的协作。
• 加速测试过程:通过Swagger UI和其他工具,快速测试API端点。
• 提高API质量:通过自动化测试,确保API的功能和性能。
• 改善用户体验:提供清晰、准确的API文档,帮助开发者更好地理解和使用API。

总之,Swagger2.0与Spring Boot 2.0的整合是一个强大的组合,可以帮助我们构建现代化的API文档管理系统,提升开发效率与团队协作能力,并快速实现接口自动化测试。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则