使用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";
    }

}
image.png

请按照以下方式编辑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进行测试。
“试用”按钮用于测试。

image.png

只需在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();
	}

}
image.png

可以直接通过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和测试所需的时间,可以视为误差。相较于使用某商用产品的图形用户界面手动操作,生产效率更高。

最後再來一個額外的好處

image.png
image.png
image.png

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

广告
将在 10 秒后关闭
bannerAds