swagger-codegen
约 2327 字大约 8 分钟
swagger-codegen
1. 使用方式
1.1 单yaml配置
1.1.1 maven配置文件
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>swaggerCodegen</artifactId>
<groupId>com.hxzj.iccs.swaggercodegen</groupId>
<version>0.3.1-RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>demo-swagger</artifactId>
<name>demo-swagger</name>
<version>1.0.0</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<swagger-annotations-version>1.5.17</swagger-annotations-version>
<jackson-version>2.12.3</jackson-version>
<yaml.path>${project.basedir}/src/main/resources/demo/demo.yaml</yaml.path>
<output.path>${project.basedir}/target/swagger</output.path>
<deploy.groupId>com.hxzj.iccs.demo</deploy.groupId>
<deploy.artifactId>rest-api</deploy.artifactId>
<deploy.version>1.0.0-RELEASE</deploy.version>
<deploy.apiPackage>${deploy.groupId}.api.rest</deploy.apiPackage>
<deploy.modelPackage>${deploy.groupId}.api.dto</deploy.modelPackage>
<deploy.invokerPackage>${deploy.groupId}.api.invoker</deploy.invokerPackage>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger-annotations-version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.swagger</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>2.4.26-hxzj</version>
<executions>
<execution>
<id>spring-pet</id>
<phase>package</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${yaml.path}</inputSpec>
<language>spring</language>
<output>${output.path}</output>
<groupId>${deploy.groupId}</groupId>
<artifactId>${deploy.artifactId}</artifactId>
<apiPackage>${deploy.apiPackage}</apiPackage>
<modelPackage>${deploy.modelPackage}</modelPackage>
<invokerPackage>${deploy.invokerPackage}</invokerPackage>
<skipOverwrite>false</skipOverwrite>
<artifactVersion>${deploy.version}</artifactVersion>
<generateSupportingFiles>true</generateSupportingFiles>
<configOptions>
<dateLibrary>legacy</dateLibrary>
<java11>true</java11>
<library>spring-boot</library>
<useBeanValidation>true</useBeanValidation>
<!--<useOptional>true</useOptional>-->
<hideGenerationTimestamp>true</hideGenerationTimestamp>
<delegatePattern>true</delegatePattern>
<serializableModel>true</serializableModel>
<useTages>true</useTages>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>install</id>
<phase>install</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<skip />
<includePluginDependencies>true</includePluginDependencies>
<includeProjectDependencies>false</includeProjectDependencies>
<mainClass>com.hxzj.iccs.swagger.base.DeployMain</mainClass>
<commandlineArgs>${output.path} ${deploy.version}</commandlineArgs>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.hxzj.iccs.swaggercodegen</groupId>
<artifactId>base</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
1.1.2 yaml配置文件
swagger: "2.0"
info:
description: "demo for codegen-swagger"
version: "1.0.0"
title: "Swagger Petstore"
termsOfService: "http://swagger.io/terms/"
contact:
email: "apiteam@swagger.io"
license:
name: "Apache 2.0"
url: "http://www.apache.org/licenses/LICENSE-2.0.html"
host: "demo.swagger.io"
basePath: "/v1/iccs"
schemes:
- "https"
- "http"
tag:
- name: User
description: User
paths:
/users:
get:
tags:
- User
summary: 分页查询用户列表
description: 分页查询用户列表
operationId: listPageUser
produces:
- "application/json"
parameters:
- name: "offset"
in: "query"
description: "offset"
required: false
type: "integer"
default: 0
- name: limit
in: query
description: limit
required: false
type: integer
format: int32
maximum: 50
minimum: 0
default: 10
- name: "userName"
in: "query"
description: "userName"
required: false
type: "string"
- name: "userID"
in: "query"
description: "userID"
required: false
type: "string"
- name: "valid"
in: "query"
description: "valid"
required: false
type: "string"
responses:
'200':
description: OK
schema:
$ref: '#/definitions/ListUserDTO'
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
post:
tags:
- User
summary: 新增用户
description: 新增用户
operationId: addUser
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- name: userDTO
in: body
description: "Create a new user parameters"
required: true
schema:
$ref: '#/definitions/UserDTO'
responses:
'201':
description: Created
schema:
$ref: '#/definitions/UserDTO'
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
/users/{userID}:
get:
tags:
- User
summary: 获取用户
description: 获取用户
operationId: getUser
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- name: userID
in: path
description: userID
required: true
type: string
responses:
'200':
description: OK
schema:
$ref: '#/definitions/UserDTO'
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
put:
tags:
- User
summary: 修改用户
description: 修改用户
operationId: updateUser
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- name: userID
in: path
description: userID
required: true
type: string
- name: userDTO
in: body
description: userDTO
required: true
schema:
$ref: '#/definitions/UserDTO'
responses:
'200':
description: OK
schema:
$ref: '#/definitions/UserDTO'
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
delete:
tags:
- User
summary: 删除用户
description: 删除用户
operationId: deleteUser
parameters:
- name: userID
in: path
description: userID
required: true
type: string
responses:
'204':
description: No Content
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
definitions:
ListUserDTO:
title: ListUserDTO
type: object
properties:
list:
type: array
items:
$ref: '#/definitions/UserDTO'
total:
type: integer
format: int32
UserDTO:
title: UserDTO
type: object
properties:
createTime:
type: string
format: date-time
iconURL:
type: string
example: https://image/1.jpg
id:
type: integer
format: int64
example: 2
userID:
type: string
example: 26b14671e2d741cbb464da7574f07489
userName:
type: string
example: 张三
userType:
$ref: '#/definitions/UserTypeEnum'
parentID:
type: string
example: '1'
updateTime:
type: string
format: date-time
UserTypeEnum:
type: string
enum:
- ADMIN
- NORMAL
- TENANT
1.2 分yaml配置
1.2.1 maven配置文件
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>swaggerCodegen</artifactId>
<groupId>com.hxzj.iccs.swaggercodegen</groupId>
<version>0.3.1-RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>demos-swagger</artifactId>
<properties>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<yamlmerge.version>1.0-SNAPSHOT</yamlmerge.version>
<yaml.path>${project.basedir}/src/main/resources/demos/demos.yaml</yaml.path>
<mergeyaml.path>${project.basedir}/target/generate.yml</mergeyaml.path>
<output.path>${project.basedir}/target/swagger</output.path>
<deploy.groupId>com.hxzj.iccs.demos</deploy.groupId>
<deploy.artifactId>rest-api</deploy.artifactId>
<deploy.version>1.0.1-RELEASE</deploy.version>
<deploy.apiPackage>${deploy.groupId}.api.rest</deploy.apiPackage>
<deploy.modelPackage>${deploy.groupId}.api.dto</deploy.modelPackage>
<deploy.invokerPackage>${deploy.groupId}.api.invoker</deploy.invokerPackage>
</properties>
<dependencies>
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger-annotations-version}</version>
</dependency>-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.swagger</groupId>
<artifactId>swagger-codegen-maven-plugin</artifactId>
<version>2.4.26-hxzj</version>
<executions>
<execution>
<id>spring-pet</id>
<phase>package</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${mergeyaml.path}</inputSpec>
<language>spring</language>
<output>${output.path}</output>
<groupId>${deploy.groupId}</groupId>
<artifactId>${deploy.artifactId}</artifactId>
<apiPackage>${deploy.apiPackage}</apiPackage>
<modelPackage>${deploy.modelPackage}</modelPackage>
<invokerPackage>${deploy.invokerPackage}</invokerPackage>
<skipOverwrite>false</skipOverwrite>
<artifactVersion>${deploy.version}</artifactVersion>
<generateSupportingFiles>true</generateSupportingFiles>
<configOptions>
<dateLibrary>legacy</dateLibrary>
<java11>true</java11>
<library>spring-boot</library>
<useBeanValidation>true</useBeanValidation>
<hideGenerationTimestamp>true</hideGenerationTimestamp>
<delegatePattern>true</delegatePattern>
<serializableModel>true</serializableModel>
<useTages>true</useTages>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>merge-yaml</id>
<phase>prepare-package</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<skip />
<includePluginDependencies>true</includePluginDependencies>
<includeProjectDependencies>false</includeProjectDependencies>
<mainClass>com.hxzj.iccs.swagger.base.MergeMain</mainClass>
<commandlineArgs>${yaml.path} ${mergeyaml.path}</commandlineArgs>
</configuration>
</execution>
<execution>
<id>install</id>
<phase>install</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<skip />
<includePluginDependencies>true</includePluginDependencies>
<includeProjectDependencies>false</includeProjectDependencies>
<mainClass>com.hxzj.iccs.swagger.base.DeployMain</mainClass>
<commandlineArgs>${output.path} ${deploy.version}</commandlineArgs>
</configuration>
</execution>
</executions>
<dependencies>
<!--<dependency>
<groupId>com.swagger.yaml</groupId>
<artifactId>yamlmerge</artifactId>
<version>${yamlmerge.version}</version>
<scope>compile</scope>
</dependency>-->
<dependency>
<groupId>com.hxzj.iccs.swaggercodegen</groupId>
<artifactId>base</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
1.2.2 yaml配置文件
1.2.2.1 dto.yaml
ListUserDTO:
title: ListUserDTO
type: object
properties:
list:
type: array
items:
$ref: '#/definitions/UserDTO'
total:
type: integer
format: int32
UserDTO:
title: UserDTO
type: object
properties:
createTime:
type: string
format: date-time
iconURL:
type: string
example: https://image/1.jpg
id:
type: integer
format: int64
example: 2
userID:
type: string
example: 26b14671e2d741cbb464da7574f07489
userName:
type: string
example: 张三
userType:
$ref: '#/definitions/UserTypeEnum'
parentID:
type: string
example: '1'
updateTime:
type: string
format: date-time
1.2.2.2 path.yaml
/users:
get:
tags:
- User
summary: 分页查询用户列表
description: 分页查询用户列表
operationId: listPageUser
produces:
- "application/json"
parameters:
- name: "offset"
in: "query"
description: "offset"
required: false
type: "integer"
default: 0
- name: limit
in: query
description: limit
required: false
type: integer
format: int32
maximum: 50
minimum: 0
default: 10
- name: "userName"
in: "query"
description: "userName"
required: false
type: "string"
- name: "userID"
in: "query"
description: "userID"
required: false
type: "string"
- name: "valid"
in: "query"
description: "valid"
required: false
type: "string"
responses:
'200':
description: OK
schema:
$ref: '#/definitions/ListUserDTO'
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
post:
tags:
- User
summary: 新增用户
description: 新增用户
operationId: addUser
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- name: userDTO
in: body
description: "Create a new user parameters"
required: true
schema:
$ref: '#/definitions/UserDTO'
responses:
'201':
description: Created
schema:
$ref: '#/definitions/UserDTO'
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
/users/{userID}:
get:
tags:
- User
summary: 获取用户
description: 获取用户
operationId: getUser
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- name: userID
in: path
description: userID
required: true
type: string
responses:
'200':
description: OK
schema:
$ref: '#/definitions/UserDTO'
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
put:
tags:
- User
summary: 修改用户
description: 修改用户
operationId: updateUser
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- name: userID
in: path
description: userID
required: true
type: string
- name: userDTO
in: body
description: userDTO
required: true
schema:
$ref: '#/definitions/UserDTO'
responses:
'200':
description: OK
schema:
$ref: '#/definitions/UserDTO'
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
delete:
tags:
- User
summary: 删除用户
description: 删除用户
operationId: deleteUser
parameters:
- name: userID
in: path
description: userID
required: true
type: string
responses:
'204':
description: No Content
'401':
description: Unauthorized
'403':
description: Forbidden
'404':
description: Not Found
1.2.2.3 common.yaml(可选)
UserTypeEnum:
type: string
description: '用户类型'
enum:
- ADMIN
- NORMAL
- TENANT
1.2.2.4 demos.yaml(汇总)
swagger: "2.0"
info:
description: "demo for codegen-swagger"
version: '1.0'
title: "API接口文档"
termsOfService: "http://swagger.io/terms/"
contact:
email: "apiteam@swagger.io"
license:
name: "Apache 2.0"
url: "http://www.apache.org/licenses/LICENSE-2.0.html"
host: "demo.swagger.io"
basePath: "/v1/iccs"
schemes:
- "https"
- "http"
tag:
- name: User
description: '用户管理'
paths:
$ref: './user/path.yaml'
definitions:
$ref: './common/common.yaml'
$ref: './user/dto.yaml'
1.2.3 插件使用工具类
1.2.3.1 MergeMain
package com.hxzj.iccs.swagger.base;
import org.apache.commons.lang3.StringUtils;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
/**
* 合并yaml文件
*/
public class MergeMain {
public static void main(String[] args) {
if (args.length != 2)
throw new IllegalArgumentException("invalid arguments passed: -" + Arrays.toString(args));
String sourceFile = args[0];
String destinationFile = args[1];
if (sourceFile == null || StringUtils.isBlank(sourceFile))
throw new IllegalArgumentException("Source file is null or blank");
if (destinationFile == null || StringUtils.isBlank(destinationFile))
throw new IllegalArgumentException("Destination file is null or blank");
Path sourceFilePath = Paths.get(sourceFile);
if (!Files.exists(sourceFilePath))
throw new IllegalArgumentException("sourceFile does not exist : " + sourceFile);
Path destFilePath = Paths.get(destinationFile);
try {
merge(sourceFilePath, destFilePath);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void merge(Path sourceFilePath, Path destFilePath) throws IOException {
Path destParentDir = destFilePath.getParent();
Files.createDirectories(destParentDir);
Files.deleteIfExists(destFilePath);
Files.createFile(destFilePath);
Path parentDir = sourceFilePath.getParent();
FileWriter fw = new FileWriter(destFilePath.toFile());
resolve(parentDir, sourceFilePath, fw, "");
fw.close();
}
private static void resolve(Path parentDir, Path sourceFilePath, FileWriter fw, String indentation) throws IOException {
Files.lines(sourceFilePath).forEach(line -> {
if (isStartWithRef(line) && isRemoteFilepath(line)) {
String indent = indentation + getIndentation(line);
String remoteRefValue = getRemoteRelativeFilePath(line);
Path remoteFilePath = getAbsolutePath(parentDir, remoteRefValue);
Path newParentDir = remoteFilePath.getParent();
try {
resolve(newParentDir, remoteFilePath, fw, indent);
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
fw.write(String.format("%s%s%n", indentation, line));
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
private static Path getAbsolutePath(Path parentDir, String remoteRefValue) {
String absFileStr = parentDir.toString() + remoteRefValue;
return Paths.get(absFileStr);
}
public static boolean isStartWithRef(String line) {
return StringUtils.trim(line).startsWith("$ref");
}
public static String getIndentation(String line) {
return StringUtils.substringBefore(line, "$ref");
}
public static boolean isRemoteFilepath(String refLine) {
String refPath = StringUtils.substringAfter(refLine, ":");
String refPathWithoutQuotes = removeQuotes(refPath);
return !StringUtils.startsWith(refPathWithoutQuotes, "#/");
}
public static String getRemoteRelativeFilePath(String refLine) {
String refPath = StringUtils.substringAfter(refLine, ":");
String relFileString = removeQuotes(refPath);
if (StringUtils.startsWith(relFileString, "."))
relFileString = StringUtils.stripStart(relFileString, ".");
return relFileString;
}
private static String removeQuotes(String refPathValue) {
String ret, trimRefValue = StringUtils.trim(refPathValue);
if (StringUtils.startsWith(trimRefValue, "'")) {
ret = StringUtils.substringBetween(trimRefValue, "'");
} else if (StringUtils.startsWith(trimRefValue, "\"")) {
ret = StringUtils.substringBetween(trimRefValue, "\"");
} else {
ret = trimRefValue;
}
return ret;
}
}
1.2.3.2 DeployMain
package com.hxzj.iccs.swagger.base;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 通过java 代码执行 mvn 打包
*/
public class DeployMain {
public static void main(String[] args) throws Exception{
System.out.println("=================start deploy swagger rest api========================");
if(args == null || args.length < 1){
throw new IllegalArgumentException("can not found swagger rest api source folder");
}
InputStream is = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try {
String sourceFolder = args[0];
String pomFile = getPomFile(sourceFolder);
Process proc = null;
String mvnCmdStr = " mvn clean install -f "+pomFile + " -Dmaven.test.skip=true ";
System.out.println("maven command = "+mvnCmdStr);
if(isWindows()){
proc = Runtime.getRuntime().exec("cmd.exe /c " + mvnCmdStr);
}else{
proc = Runtime.getRuntime().exec("sudo " + mvnCmdStr);
}
is = proc.getInputStream();
inputStreamReader = new InputStreamReader(is);
bufferedReader = new BufferedReader(inputStreamReader);
String line;
while ((line=bufferedReader.readLine())!=null) {
System.out.println(line);
}
int processCode = proc.waitFor();
System.out.println("Process code: " + processCode);
proc.destroy();
System.out.println("=================end deploy swagger rest api========================");
if(processCode!=0){
throw new Exception("error to deploy swagger rest api");
}
}finally {
try {
if(bufferedReader!=null) {
bufferedReader.close();
}
if(inputStreamReader!=null) {
inputStreamReader.close();
}
if(is!=null) {
is.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
private static String getPomFile(String sourceFolder){
if(sourceFolder.endsWith("/") || sourceFolder.endsWith("\\")){
return sourceFolder + "pom.xml";
}else{
return sourceFolder + File.separator + "pom.xml";
}
}
private static boolean isWindows(){
String osName = System.getProperties().getProperty("os.name");
if(osName.equals("Linux"))
{
return false;
}else{
return true;
}
}
}
2. 原理分析
2.1 swagger-codegen-maven-plugin依赖
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-codegen</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!-- <version>4.12</version> -->
<scope>test</scope>
</dependency>
</dependencies>
2.2 反编译 swagger-codegen-maven-plugin
CodeGenMojo.execute() 最终通过 (new DefaultGenerator()).opts(input).generate(); 进行代码生成,刚好插件又依赖了 swagger-codegen-2.4.26-hxzj.jar 包,反编译该 jar 包
2.3 反编译 swagger-codegen
发现里面有很多 .mustache 结尾的文件,这是以 mustache 语法编写的模板文件,在生成代码时会进行调用。