从Swagger到OpenAPI规范-SpringBoot集成StepByStep

0-1开始Java语言编程之路
一、Ubuntu下Java语言环境搭建 | MacOS下使用Jenv管理多JDK版本
二、Ubuntu下Docker环境安装 | MacOS下Docker安装与配置
三、使用Docker搭建本地Nexus Maven私有仓库
四、Ubuntu下使用VisualStudioCode进行Java开发
五、从Swagger到OpenAPI,SpringBoot集成StepByStep
六、OpenAPI Generator Maven 插件配置详解(SpringBoot集成)

前言

首先我们来看一个熟悉的界面,没错,就是大家熟悉的Swagger。
swagger ui demo
相信做过Java项目的同学应该都使用过Swagger,至少项目会集成SwaggerUI,通过集成SwaggerUI,可获得如下几个好处:

  1. 自动化文档生成: SwaggerUI 可以根据你项目中使用 Swagger/OpenAPI 规范(通常通过 annotations 注解在 Java 代码中)定义的 API 接口,自动生成美观、易于理解的 API 文档。
  2. 可视化界面: SwaggerUI 以 交互式、可视化的 Web 页面 形式展示 API 文档。相比于传统的文本或 PDF 文档,SwaggerUI 更加直观易用,开发者可以轻松浏览 API 的 endpoints、参数、请求体、响应示例等信息。
  3. 在线测试工具: 开发者可以直接在 SwaggerUI 页面上,填写参数、设置请求头等信息,发送 API 请求,并查看 实时的响应结果。

SpringBoot集成Swagger-UI

以下的代码都在github可以下载,请访问Github项目:swagger-ui-demo

一、添加Maven依赖

以SpringBoot 3.x 集成Swagger-UI为例

<dependencies>
    <!-- Spring Boot Starter Web(确保项目为 Web 项目) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- springdoc-openapi 集成 Swagger UI -->
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
        <version>2.8.5</version>
    </dependency>
</dependencies>

二、Springdoc配置( application.yml )

springdoc:
  api-docs:
    path: /v3/api-docs
  swagger-ui:
    path: /dev-tools/

三、在SpringBoot应用中定义API接口

1) SpringBootApplication

package com.txzq.swagger_ui;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Contact;
import io.swagger.v3.oas.annotations.info.Info;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@OpenAPIDefinition(
        info = @Info(
                title = "TXZQ Service API 文档", version = "1.0.0",
                description = "这是一个基于 Spring Boot 3.x 和 Swagger UI 的 API 文档示例", contact = @Contact(
                name = "TXZQ Service Team", email = "service@txzq.com", url = "https://service.txzq.com"),
                termsOfService = "https://www.txzq.com/terms/"

        ))
public class SwaggerUiApplication {

    public static void main(String[] args) {
        SpringApplication.run(SwaggerUiApplication.class, args);
    }
}

2) Controller API 定义

package com.txzq.swagger_ui.controller;


import com.txzq.swagger_ui.common.CommonResponse;
import com.txzq.swagger_ui.common.FileUploadRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
public class HelloController {
@Operation(
            summary = "uploads an image",
            description = "",
            operationId = "uploadImage",
            tags = {"User API"},
            parameters = {@Parameter(
                    name = "userId",
                    in = ParameterIn.PATH,
                    description = "ID of User to update",
                    required = true,
                    schema = @Schema(
                            type = "integer",
                            format = "int64"))},
            requestBody = @RequestBody(
                    description = "Additional information and image to upload",
                    required = false,
                    content = @Content(
                            mediaType = "multipart/form-data",
                            schema = @Schema(
                                    type = "object",
                                    implementation = FileUploadRequest.class))),
            responses = {@ApiResponse(
                    responseCode = "200",
                    description = "successful operation",
                    content = @Content(
                            mediaType = "application/json",
                            schema = @Schema(implementation = CommonResponse.class)))})
    @PostMapping("/{userId}/uploadImage")
    public ResponseEntity<CommonResponse> uploadImage(
            @PathVariable("userId") Long userId,
            @RequestPart("uploadRequest") FileUploadRequest uploadRequest)
    {
       return ResponseEntity.ok(new CommonResponse());
    }
}

四、启动Application,访问swagger-ui

当然在做完所有这些准备工作之后,请别忘记了使用mvn clean install对项目进行构建
build first
** 打开Edge或者Chrome **
启动应用,并访问http://localhost:8080/dev-tools/,这时会跳转到http://localhost:8080/dev-tools/swagger-ui/index.html
swagger-ui
查看api-docsapi-docs到这里,大家所熟悉的Springboot集成Swagger-UI就已经实现了。这种熟悉的开发模式是先实现代码,再生成API文档。
细心的同学可能会发现最后一步所访问的:http://localhost:8080/v3/api-docs这个地址,我们可以得到一个json文件,它就是我们今天要讲的第二部分内容,基于OpenAPI规范的API Spec的定义。

OpenAPI 规范简介

OpenAPI规范的由来

一开始Swagger项目的目的是通过代码注解生成可交互的API文档,后来Swagger项目被捐赠给了Linux基金会,并更名为OpenAPI规范(OAS),成为了行业标准。

制定规范的核心目标

OpenAPI 规范旨在解决传统 API 开发中的痛点:

  • 文档与实现脱节:手动维护文档易出错,且更新滞后。
  • 缺乏统一描述标准:不同团队或工具间的接口描述方式混乱,协作成本高。
  • 工具链割裂:缺乏机器可读的 API 定义,难以自动化生成代码、测试用例或 Mock 服务。

解决的核心问题

  • 标准化 API 描述
    提供统一的 YAML/JSON 格式,明确定义 API 的端点、参数、响应、安全等细节,消除歧义。
  • 自动化工具生态
    基于规范文件,可自动化生成文档、客户端/服务端代码、测试用例、Mock 服务器等。
  • 提升协作效率
    前后端团队可并行开发:前端通过 Mock 数据模拟接口,后端专注于实现逻辑,减少等待。

带来的开发体验提升

  • 文档即代码
    通过工具(如 Swagger UI、Redoc)自动生成实时、可交互的 API 文档,支持在线测试接口。
  • 代码生成
    使用 Swagger Codegen 或 OpenAPI Generator 生成多语言客户端 SDK 和服务端框架代码,减少重复劳动。
  • Mock 服务
    工具(如 Prism、Postman)可基于规范快速创建模拟 API,支持前后端分离开发。
  • 自动化测试与校验
    利用规范验证 API 实现是否符合设计(如 Dredd),或生成测试用例。
  • 生态整合
    与主流工具链(如 Postman、Apigee、AWS API Gateway)无缝集成,支持 API 全生命周期管理。

一种新的开发方式:API First

OpenAPI 规范通过 标准化 API 描述推动工具自动化,解决了 API 开发中的协作低效、维护成本高等问题,成为现代 API 优先(API-First)开发模式的基石。无论是独立开发者还是大型团队,都能通过其生态显著提升开发效率与质量。

基于API First方式的开发流程


第一步、创建一个空的SpringBoot项目

访问 https://start.spring.io,输入Project Metadata,无需任何Dependency,直接Generate。
empty-springboot-application


第二步、基于OpenAPI规范定义API Spec

在SpringBoot Application的/src/main/resources/目录下创建一个 api-spec.yaml,内容如下

openapi: "3.1.0"
info:
  title: "Demo Service API 文档"
  description: "这是一个基于 Spring Boot 3.x 和 Swagger UI 的 API 文档示例"
  termsOfService: "https://www.txzq.com/terms/"
  contact:
    name: "Demo Service Team"
    url: "https://service.txzq.com/demo"
    email: "demoservice@txzq.com"
  version: "1.0.0"
servers:
  - url: "http://localhost:8080/"
    description: "Generated server url"
paths:
  "/{userId}/uploadImage":
    post:
      tags:
        - "User"
      summary: "uploads an image"
      operationId: "uploadImage"
      parameters:
        - name: "userId"
          in: "path"
          description: "ID of User to update"
          required: true
          schema:
            type: "integer"
            format: "int64"
      requestBody:
        description: "Additional information and image to upload"
        content:
          multipart/form-data:
            schema:
              $ref: "#/components/schemas/FileUploadRequest"
      responses:
        "200":
          description: "successful operation"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CommonResponse"
  "/hello":
    get:
      tags:
        - "Hello"
      operationId: "hello"
      responses:
        "200":
          description: "OK"
          content:
            "*/*":
              schema:
                type: "string"
components:
  schemas:
    FileUploadRequest:
      type: "object"
      properties:
        avatar:
          type: "string"
          description: "User's avatar"
        nickname:
          type: "string"
          description: "The user's Nick Name"
        image:
          type: "string"
          format: "binary"
          description: "image to upload"
    CommonResponse:
      type: "object"
      description: "API response"
      properties:
        code:
          type: "integer"
          format: "int32"
          description: "response code"
          example: 200
        message:
          type: "string"
          description: "response message"
          example: "successful operation"

总体来讲,该API Spec文档分为5个部分:

  • OpenAPI 版本信息

  • API 文档的元数据(info 节点)

    • title:文档标题,即“Demo Service API 文档”。
    • description:对该 API 的简短描述,说明这是一个基于 Spring Boot 3.x 和 Swagger UI 的示例。
    • termsOfService:服务条款的链接。
    • contact:联系方式,包含团队名称、网址和邮箱,便于用户在遇到问题时联系服务提供方。
    • version:API 版本,这里为 1.0.0。
  • 服务器信息(servers 节点)

    • 定义了一个服务器地址,即本地服务器 http://localhost:8080/,同时提供了描述信息。
  • 路径与操作定义(paths 节点)

    • 路径:/{userId}/uploadImage,其中 {userId} 是路径参数。
    • 方法:HTTP POST,用于上传图片。
    • tags:接口归类到 “User” 分组。
    • summary:简短说明接口的功能 —— 上传图片。
    • operationId:操作唯一标识符 “uploadImage”。
    • parameters:
      定义了一个路径参数 userId,其类型为 integer(64 位),用于指定需要更新图片的用户 ID。
    • requestBody:
      描述了请求体,说明是“Additional information and image to upload”。
      内容类型为 multipart/form-data,使用 $ref 引用了在 components.schemas 中定义的 FileUploadRequest 模型,说明请求体结构由该模型描述。
    • responses:
      对应状态码 200,表示操作成功,响应内容类型为 application/json,引用了 CommonResponse 模型。
  • 组件定义(components 数据节点)

    • 定义了一个对象类型模型CommonResponse,用于描述 API 的通用响应格式。
    • code:整数类型(32 位),用于表示响应代码,示例值为 200。
    • message:字符串类型,用于描述响应消息,示例为 “successful operation”。

第三步、创建一个pom-for-api-generate.xml

该文件仅仅用于生成基础代码

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.4.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.txzq</groupId>
	<artifactId>api-first-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>api-first-demo</name>
	<description>Demo project for Spring Boot </description>

	<properties>
		<openapi-generator.version>7.10.0</openapi-generator.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.openapitools</groupId>
			<artifactId>openapi-generator</artifactId>
			<version>${openapi-generator.version}</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.openapitools</groupId>
				<artifactId>openapi-generator-maven-plugin</artifactId>
				<version>${openapi-generator.version}</version>
				<executions>
					<execution>
						<goals>
							<goal>generate</goal>
						</goals>
						<configuration>
							<inputSpec>
								${project.basedir}/src/main/resources/api-spec.yaml
							</inputSpec>
							<generatorName>spring</generatorName>
							<apiPackage>com.txzq.platform.userservice.api</apiPackage>
							<modelPackage>com.txzq.platform.domain.model</modelPackage>
							<additionalProperties>
								<generateExamples>false</generateExamples>
							</additionalProperties>
<!--							<supportingFilesToGenerate>-->
<!--								ApiUtil.java-->
<!--							</supportingFilesToGenerate>-->
							<configOptions>
								<delegatePattern>true</delegatePattern>
								<reactive>false</reactive>
								<performBeanValidation>true</performBeanValidation>
								<useBeanValidation>true</useBeanValidation>
								<useSpringBoot3>true</useSpringBoot3>
								<basePackage>com.txzq.platform.userservice</basePackage>
								<configPackage>com.txzq.platform.userservice.config</configPackage>
								<hideGenerationTimestamp>true</hideGenerationTimestamp>
								<useEnumCaseInsensitive>true</useEnumCaseInsensitive>
								<useTags>true</useTags>
							</configOptions>
							<output>${project.basedir}</output>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

第四步、生成基础代码

#在工作空间根目录下边执行如下mvn命令
arsenal@txzq1899:~/Workspace/api-first-demo$ mvn -f pom-for-api-generate.xml clean generate-sources
。。。。。。
。。。。。。
。。。。。。
。。。。。。
[INFO] writing file /home/arsenal/Workspace/api-first-demo/src/main/java/com/txzq/platform/userservice/OpenApiGeneratorApplication.java
[INFO] writing file /home/arsenal/Workspace/api-first-demo/src/test/java/com/txzq/platform/userservice/OpenApiGeneratorApplicationTests.java
[INFO] writing file /home/arsenal/Workspace/api-first-demo/src/main/java/com/txzq/platform/userservice/RFC3339DateFormat.java
[INFO] writing file /home/arsenal/Workspace/api-first-demo/src/main/resources/application.properties
[INFO] writing file /home/arsenal/Workspace/api-first-demo/src/main/java/com/txzq/platform/userservice/config/HomeController.java
[INFO] writing file /home/arsenal/Workspace/api-first-demo/src/main/resources/openapi.yaml
[INFO] writing file /home/arsenal/Workspace/api-first-demo/src/main/java/com/txzq/platform/userservice/config/SpringDocConfiguration.java
[INFO] writing file /home/arsenal/Workspace/api-first-demo/src/main/java/com/txzq/platform/userservice/api/ApiUtil.java
[INFO] Skipped /home/arsenal/Workspace/api-first-demo/.openapi-generator-ignore (Skipped by supportingFiles options supplied by user.)
[INFO] writing file /home/arsenal/Workspace/api-first-demo/.openapi-generator/VERSION
[INFO] writing file /home/arsenal/Workspace/api-first-demo/.openapi-generator/FILES
################################################################################
# Thanks for using OpenAPI Generator.                                          #
# Please consider donation to help us maintain this project 🙏                 #
# https://opencollective.com/openapi_generator/donate                          #
################################################################################
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------


#使用mvn进行项目构建
arsenal@txzq1899:~/Workspace/api-first-demo$ mvn clean install
等待编译成功

第五步、IDEA 打开项目

这里需要注意一点,我们初始化项目时,脚手架工具为我们生成了项目的SpringBootApplication,以及对应的test文件,这里我们需要删除,使用openapi-generator生成的。
api-first-demo-in-IDEA
我们来看一下生成的文件清单:

  • com.txzq.platform.domain.model.CommonResponse
  • com.txzq.platform.userservice.api.xxxxApi
  • com.txzq.platform.userservice.api.xxxxApiController
  • com.txzq.platform.userservice.api.xxxxApiDelegate
  • com.txzq.platform.userservice.config.HomeController
  • com.txzq.platform.userservice.config.SpringDocConfiguration
  • com.txzq.platform.userservice.OpenApiGeneratorApplication
  • com.txzq.platform.userservice.RFC33390DateFormat
  • pom.xml

第六步、增加实现类

  • 首先创建package:com.txzq.platform.userservice.api.impl
  • 创建一个实现类:HelloApiImpl
package com.txzq.platform.userservice.api.impl;

import com.txzq.platform.userservice.api.HelloApiDelegate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;

@Controller
public class HelloApiImpl implements HelloApiDelegate {

    @Override
    public ResponseEntity<String> hello() {
        return ResponseEntity.ok("Hello, World!");
    }
}

第七步、配置spring-docs

创建一个application.yml文件,内容如下

springdoc:
  api-docs:
    path: /v3/api-docs
    inline-schemas: false
  swagger-ui:
    path: /dev-tools/

openapi:
  demoServiceAPI:
    base-path: /

说明一点,demoServiceAPI 是因为我们的api-spec.yaml文件中,info.title的配置如下:

info:
  title: "Demo Service API 文档"

另外,我们以HelloApiController为例:

@Generated(value = "org.openapitools.codegen.languages.SpringCodegen", comments = "Generator version: 7.10.0")
@Controller
@RequestMapping("${openapi.demoServiceAPI.base-path:}")
public class HelloApiController implements HelloApi {

    private final HelloApiDelegate delegate;

    public HelloApiController(@Autowired(required = false) HelloApiDelegate delegate) {
        this.delegate = Optional.ofNullable(delegate).orElse(new HelloApiDelegate() {});
    }

    @Override
    public HelloApiDelegate getDelegate() {
        return delegate;
    }

}

我们可以看到RequestMapping会引用openapi.demoServiceAPI.base-path的值,所以我们需要在application.yml中进行配置。

第八步、启动SpringBootApplication,访问swagger-ui,验证hello接口

启动应用,并访问http://localhost:8080/dev-tools/,这时会跳转到http://localhost:8080/dev-tools/swagger-ui/index.html,也就是我们上面熟悉的页面。
访问:http://localhost:8080/hello, 我们可以正常的看到:Hello, World!
hello-world
这里有一点需要注意,如果我们没有创建上面的HelloApiImpl实现类,那么我们得到的结果是501(NOT IMPLEMENT),在HelloApiDelegate中可以看到如下相关的代码

	default ResponseEntity<String> hello() {
        return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);

    }

那么,到这里我们就完整的体验了一把API First方式的开发流程,总的来讲就是先基于OpenAPI规范,先进行API的设计,然后通过code generator来自动生成基础代码,最后自己写具体的实现类来达成业务需求。

思考题

  • 关于生成的pom.xml
  • 关于maven plugin的配置
  • 关于supportingFilesToGenerate

想要了解更多,我将带你更深入的学习openapi-generator源码,期待下一稿。

关注我的公众号

欢迎大家关注、点赞、转发,一起交流软件开发、架构设计、云原生技术。
TXZQ聊IT技术与架构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值