前言

关于 Swagger 和 OpenAPI 的介绍,请看我的另一篇文章:Spring Boot 中使用 SpringFox 整合 Swagger 3(OpenAPI 3)生成 API 文档 ,文章有介绍 Swagger 和 OpenAPI 和 Swagger 3(OpenAPI 3)的新注解介绍及使用方法,也建议你阅读本文前先去看看。

本文仅介绍在 Spring Boot 中使用 Springdoc 整合 Swagger 3.0(OpenAPI 3)。

示例代码已上传到 Github:spring-boot-springdoc-swagger3

springdoc-openapi 介绍

springdoc-openapi java 库可助于我们在 Spring Boot 项目自动生成 API 文档。springdoc-openapi 通过在运行时检查应用程序来根据 Spring 配置、类结构和各种注释推断 API 语义,自动生成 JSON/YAML 和 HTML 格式的 API 文档。

springdoc-openapi 支持:

  • OpenAPI 3
  • Spring Boot (v1 and v2)
  • 支持 JSR-303 校验规范,如 @NotNull, @Min, @Max, @Size 等注解
  • swagger-ui
  • OAuth 2
  • GraalVM 原生镜像

Swagger 3.0(Open API 3.0)注解介绍

关于注解的介绍请看我的另一篇文章 Spring Boot 中使用 SpringFox 整合 Swagger 3(OpenAPI 3)生成 API 文档 ,里面有详细的介绍和示例代码,这里就不过多赘述了。

使用

添加依赖

编辑 pom.xml 文件,添加依赖:

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.5.9</version>
</dependency>

这将自动把 swagger-ui 部署到 Spring Boot 应用中:

  • 文档将以 HTML 格式展示,使用官方 swagger-ui jars
  • Swagger UI 页面将通过 http://server:port/context-path/swagger-ui.html 访问
  • OpenAPI 描述将通过 http://server:port/context-path/v3/api-docs 访问,提供 JSON 格式
  • 文档提供 yaml 格式,位于以下路径:/v3/api-docs.yaml

启动项目后,使用浏览器访问:http://localhost/swagger-ui.html 就能看到 Swagger UI 展示的 API 文档。

swagger-ui

添加 Swagger 配置

新增配置类 SwaggerConfig,用于配置全局 API 文档信息:

@OpenAPIDefinition(
        tags = {
            @Tag(name = "用户管理", description = "用户模块操作"),
            @Tag(name = "角色管理", description = "角色模块操作")
        },
        info = @Info(
            title = "用户接口 API 文档",
            description = "用户数据管理......",
            version = "1.0.0",
            contact = @Contact(name = "lanweihong", email = "986310747@qq.com", url = "https://www.lanweihong.com"),
            license = @License(name = "Apache 2.0", url = "http://www.apache.org/licenses/LICENSE-2.0.html")
        ),
        servers = {
            @Server(description = "生产环境服务器", url = "https://xxxx.com/api/v1"),
            @Server(description = "测试环境服务器", url = "https://test.xxxx.com/api/v1")
        },
        security = @SecurityRequirement(name = "Oauth2"),
        externalDocs = @ExternalDocumentation(
                description = "项目编译部署说明",
                url = "http://localhost/deploy/README.md"
        )
)
@Configuration
public class SwaggerConfig {
}

添加 Controller

编写 Controller:

@Tag(name = "用户管理", description = "用户数据增删改查")
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Operation(summary = "查询用户列表", description = "返回所有用户数据")
    @GetMapping("")
    public JsonResult<List<UserVO>> getUserList(@Parameter(description = "用户名") @RequestParam(value = "username", required = false) String userName) {
        List<UserVO> result = new ArrayList<>();
        // TODO
        return JsonResult.ok(result);
    }

    @Operation(summary = "通过用户名查询用户", description = "根据用户名查询用户详细信息")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "请求成功"),
            @ApiResponse(responseCode = "404", description = "用户不存在", content = @Content)
    })
    @GetMapping("/{username}")
    public JsonResult<UserVO> getUserByName(@Parameter(description = "用户名", required = true) @PathVariable("username") String userName) {
        // TODO
        return JsonResult.ok();
    }

    @Operation(summary = "新增用户")
    @PostMapping("")
    public JsonResult<UserVO> addUser(@Parameter(required = true) @Valid @RequestBody UserParam param) {
        // TODO
        return JsonResult.ok();
    }

    @Operation(summary = "修改用户")
    @PutMapping("")
    public JsonResult<UserVO> updateUser(@Parameter(description = "用户参数", required = true) @Valid @RequestBody UserParam param) {
        // TODO
        return JsonResult.ok();
    }

    @Operation(summary = "删除用户")
    @DeleteMapping("/{username}")
    public JsonResult<UserVO> deleteUserByName(@Parameter(name = "username", in = ParameterIn.PATH, description = "用户名", required = true) @PathVariable("username") String userName) {
        // TODO
        return JsonResult.ok();
    }

    @Operation(summary = "测试新增用户接口", hidden = true)
    @PostMapping("/test")
    @Hidden
    public JsonResult<UserVO> testAddUser(@Parameter(required = true) @Valid @RequestBody UserParam param) {
        // TODO
        return JsonResult.ok();
    }
}

添加相关 POJO

  1. 添加 UserParam,用于接收前端参数:

    @Getter
    @Setter
    @Schema(description = "用户参数实体")
    public class UserParam {
    
     @NotBlank(message = "用户名不能为空")
     @Schema(description = "用户名")
     private String userName;
    
     @Schema(name = "roles", description = "角色id列表")
     @NotNull(message = "角色id列表不能为空")
     @Size(min = 1)
     private Set<String> roleList;
    
     @NotBlank(message = "密码不能为空")
     @Schema(description = "密码,6-18位,包含大小写、数字及特殊字符")
     @Size(min = 6, max = 18)
     private String password;
    
     @Schema(example = "zhangsan@lanweihong.com", description = "邮箱")
     private String email;
    
     @Schema(description = "年龄")
     @Min(value = 1, message = "最小年龄为1")
     @Max(value = 150, message = "最大年龄为150")
     private Integer age;
    }

这里 UserParam 使用 JSR-303 Bean Validation 注解来校验参数,springdoc-openapi 会帮我们生成相应的说明信息,如下图:

Swagger UI中的说明信息

全局异常处理

新增全局异常处理类 GlobalExceptionHandler

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(InvalidParameterException.class)
    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
    public JsonResult<String> bindInvalidParameterExceptionHandler(InvalidParameterException e) {
        log.error("错误的请求,参数无效:", e);
        return JsonResult.error(e.getMessage());
    }

    @ResponseStatus(code = HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = BadRequestException.class)
    public JsonResult<String> bindBadRequestExceptionHandler(BadRequestException e) {
        log.error("错误的请求:", e);
        return JsonResult.error(e.getError());
    }

    @ResponseStatus(code = HttpStatus.NOT_FOUND)
    @ExceptionHandler(value = NotFoundException.class)
    public JsonResult<String> bindNotFoundExceptionHandler(NotFoundException e) {
        log.error("资源未找到:", e);
        return JsonResult.error(e.getError());
    }

    // 其他异常处理......
}

分组

  1. 可以在通过配置 application.yml 来设置分组:
springdoc:
  # 分组配置
  group-configs:
    - group: All
      packagesToScan: com.lanweihong.springdoc.swagger.controller
      pathsToMatch: /api/**
    - group: User
      packagesToScan: com.lanweihong.springdoc.swagger.controller.user
      pathsToMatch: /api/users/**
    - group: Role
      packagesToScan: com.lanweihong.springdoc.swagger.controller.role
      pathsToMatch: /api/roles/**
  1. 也可以在配置类中添加 GroupedOpenApi

    @Configuration
    public class SwaggerConfig {
    
         @Bean
         public GroupedOpenApi userApi() {
                 return GroupedOpenApi.builder()
                         .group("User")
                         .pathsToMatch("/api/users/**")
                         .build();
         }
    
         @Bean
         public GroupedOpenApi roleApi() {
                 return GroupedOpenApi.builder()
                         .group("Role")
                         .pathsToMatch("/api/roles/**")
                         .build();
         }
    }

注意:这两个方法只能选择一种来配置,比如在 application.yml 配置了就不要再通过代码添加 GroupedOpenApi ,否则会报错,除非你设置的 group 不一样。

  1. 为特定组设置自定义的 API 文档信息

在以上的 SwaggerConfig 配置类中,我们使用 @OpenAPIDefinition 来设置全局的 API 文档信息。但有时,我们想切换到某个组(group)的时候,API 文档信息显示关于这个组的相关信息,而显示全局的信息。这时,我们可以定义一个 OpenApiCustomiser 添加到 GroupedOpenApi 中:

@Configuration
public class SwaggerConfig {

        @Bean
        public GroupedOpenApi userApi() {
                return GroupedOpenApi.builder()
                        .group("User")
                        // 指定路径
                        .pathsToMatch("/api/users/**")
                        // 指定特定的 API 文档信息
                        .addOpenApiCustomiser(userApiCustomiser())
                        .build();
        }

        /**
         * 定义 OpenApiCustomiser ,用于指定的 group
         * @return
         */
        public OpenApiCustomiser userApiCustomiser() {
                return openApi -> openApi.info(new io.swagger.v3.oas.models.info.Info()
                .title("用户管理 API 文档")
                        .description("实现对用户数据的增删改查等操作")
                        .version("1.0")
                        .contact(new io.swagger.v3.oas.models.info.Contact().name("lanweihong").email("986310747@qq.com")));
        }
}

在 Swagger UI 中看到 User 组的文档信息已更新显示,不再是全局的文档信息。

用户分组 API 文档信息

测试

启动项目,访问 http://localhost:8080/swagger-ui.html 访问 Swagger UI。

主页面:

主页面

请求接口描述:

请求描述

分组:

分组

实体类描述:

实体类描述

至此,Spring Boot 中使用 Springdoc 整合Swagger 3(OpenAPI 3)的介绍已完成。

总结

本文仅介绍常用的注解用法及配置,想要了解更多的用法请查看官方文档:OpenAPI 3 Library for spring-boot

使用到的代码已上传到 Github:spring-boot-springdoc-swagger3

参考文档

  1. OpenAPI 3 Library for spring-boot
  2. Swagger3 注解使用(Open API 3)
文章目录