使用springdoc-openapi来自动生成API文档,自动生成的文档可用于自动生成API客户端代码
-
- 本検証で利用した製品
- Spring Boot v3.0.2
关于先编写API文档还是先编写代码,有不同的意见。
个人认为先编写文档,然后编写与之相匹配的代码在现实中很困难,所以我认为先在Java端进行设计,并采用自动生成的方法是最好的。
-
- RESTコントローラの作成
- 文字列”HelloWorld”を返すだけの簡単なコントローラ
package com.example.demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(path="/")
public class TestController {
@RequestMapping(path="/hello", method=RequestMethod.GET)
public String hello() {
return "HelloWorld";
}
}

请按照以下方式编辑pom.xml文件来设置springdoc。
添加依赖项。
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
</dependency>
pom.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.0.2</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
应用程序属性
springdoc.api-docs.path=/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
在重新启动后,可以通过上述设置的路径下载文件或在浏览器中查看。
还提供以HTML格式排版的文档,并且可以在此界面上对API进行测试。
“试用”按钮用于测试。

只需在pom.xml文件中添加4行,并在application.properties文件中添加2行即可生成API文档。
接下来,从生成的API文档中自动创建API客户端源代码的方式。
下载openapi-generator-cli-xxx.jar,并使用一个java命令即可自动生成源代码。
java -jar openapi-generator-cli-6.3.0.jar generate -i ./api-docs.yaml --api-package com.example.demo --model-package com.example.demo --invoker-package com.example.demo --group-id com.example --artifact-id demo --artifact-version 0.0.1-SNAPSHOT -g java -p java8=true --library resttemplate -o spring-openapi-generator-api-client
自动生成的代码中包含了用于单元测试的代码。
将src文件夹中的所有源代码复制到API客户端项目的src文件夹中。
调用API的源代码
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping(path="/")
@RequiredArgsConstructor
public class TestController {
@Autowired
private TestControllerApi testApi;
@RequestMapping(path="/apiclient", method=RequestMethod.GET)
public String hello() {
String result = testApi.hello();
return result;
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

可以直接通过API返回的HelloWorld进行显示。
用于API和API客户端在不同端口上启动的Spring Boot配置。
application.properties
server.port=8081
API客户端的pom.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.0.2</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>apiClient</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>apiClient</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<url>https://github.com/openapitools/openapi-generator</url>
<scm>
<connection>scm:git:git@github.com:openapitools/openapi-generator.git</connection>
<developerConnection>scm:git:git@github.com:openapitools/openapi-generator.git</developerConnection>
<url>https://github.com/openapitools/openapi-generator</url>
</scm>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<!-- HTTP client: Spring RestTemplate -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- JSON processing: jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.5</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-core</artifactId>
<version>6.3.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
创建@Configuration
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class TestIntegrationConfig {
@Bean
@Primary
public TestControllerApi petApi() {
return new TestControllerApi(apiClient());
}
@Bean
public ApiClient apiClient() {
return new ApiClient();
}
}
Spring Boot的主类
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
@SpringBootApplication
@Import(TestIntegrationConfig.class)
public class ApiClientApplication {
public static void main(String[] args) {
SpringApplication.run(ApiClientApplication.class, args);
}
}
到达这个步骤需要相当一段时间,但对于第二个及其后的API来说
■ 创建API(根据业务逻辑的复杂程度)
■ 创建API文档(立即完成与代码没有差异的文档)
■ 执行代码生成器并复制生成的代码(几分钟)
■ 创建@Configuration(几分钟)
■ API调用部分的代码(只需调用方法,所以几分钟)
在实际案例中,我们可以建立更智能的方法来调用API或组合他们,因为这只是简单的方法调用,所以对于创建API和测试所需的时间,可以视为误差。相较于使用某商用产品的图形用户界面手动操作,生产效率更高。
最後再來一個額外的好處



按照某商用产品建议的三层架构来实施可能会降低性能。如果增加CPU,成本会增加,所以要小心。