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。
相信做过Java项目的同学应该都使用过Swagger,至少项目会集成SwaggerUI,通过集成SwaggerUI,可获得如下几个好处:
- 自动化文档生成: SwaggerUI 可以根据你项目中使用 Swagger/OpenAPI 规范(通常通过 annotations 注解在 Java 代码中)定义的 API 接口,自动生成美观、易于理解的 API 文档。
- 可视化界面: SwaggerUI 以 交互式、可视化的 Web 页面 形式展示 API 文档。相比于传统的文本或 PDF 文档,SwaggerUI 更加直观易用,开发者可以轻松浏览 API 的 endpoints、参数、请求体、响应示例等信息。
- 在线测试工具: 开发者可以直接在 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对项目进行构建
** 打开Edge或者Chrome **
启动应用,并访问http://localhost:8080/dev-tools/,这时会跳转到http://localhost:8080/dev-tools/swagger-ui/index.html
查看api-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。
第二步、基于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生成的。
我们来看一下生成的文件清单:
- 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!
这里有一点需要注意,如果我们没有创建上面的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源码,期待下一稿。
关注我的公众号
欢迎大家关注、点赞、转发,一起交流软件开发、架构设计、云原生技术。