Swagger结合mustache模板生成后台接口代码、以及前后台建模代码
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Swagger结合mustache模板⽣成后台接⼝代码、以及前后台建
模代码
之前项⽬中使⽤的的thrift来建模,维护前后台模型以及rest接⼝,前台使⽤的是angular2;
但是使⽤thrift只能⽣成建模,后台的rest接⼝的Controller⽂件还是需要⼿动去写,⼀旦接⼝改动就会涉及到很多⽅⾯。
由此准备使⽤Swagger和mustache模板来做⼀个maven插件直接⽣成前台ts⽂件和后台java⽂件以及rest接⼝⽂件。
只需要维护swagger的yaml⽂件。
yaml⽂件:
swagger: "2.0"
info:
description: "This is a sample server Petstore server."
version: "1.0.0"
title: "Swagger Petstore"
termsOfService: "http://swagger.io/terms/"
contact:
email: "apiteam@swagger.io"
license:
name: "Apache 2.0"
url: "/licenses/LICENSE-2.0.html"
host: "petstore.swagger.io"
basePath: "/v2"
#tags Controller类名
tags:
- name: "UserRestApi"
schemes:
- "https"
- "http"
# paths rest接⼝相关信息
paths:
/user/{username}:
#get 请求⽅式 post put...
get:
tags:
- "UserRestApi"
summary: "Get user by user name"
description: ""
#operationId:接⼝⽅法名
operationId: "getUserByName"
produces:
- "application/xml"
- "application/json"
parameters:
- name: "username"
#in:path路径传参(占位符传参) body消息体传参 query问号传参 ...
in: "path"
description: "The name that needs to be fetched. Use user1 for testing. "
required: true
type: "string"
responses:
200:
description: "successful operation"
# schema $ref ⾃定义模型(⾮基础数据类型)
schema:
$ref: "#/definitions/User"
400:
description: "Invalid username supplied"
404:
description: "User not found"
#definitions 前后台模型相关信息
definitions:
User:
type: object
properties:
id:
type: integer
#int64 Long int32 Integer
format: int64
petId:
type: integer
format: int64
quantity:
type: integer
format: int32
shipDate:
type: string
format: date-time
status:
type: string
description: Order Status
enum:
- placed
- approved
- delivered
complete:
type: boolean
⽣成的Controller⽂件:
package ni.jun.yang.api;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import er;
@RestController
public class UserRestApi
{
//接⼝注⼊,逻辑均在实现类中实现
UserRestApiHandle handle;
@RequestMapping(value = "/user/{userName}",method = RequestMethod.GET)
public User getUserByName(HttpServletRequest request, @PathVariable String userName) {
//TODO
return handle.getUserByName(request, username);
}
}
同时还⽣成对应User类,UserRestApiHandle 接⼝,对于"/user/{username}"接⼝的逻辑实现只需要在UserRestApiHandle接⼝的实现类中去具体实现即可。
Controller类,UserRestApiHandle 接⼝,java模型,前台ts模型均是根据yaml⽂件⾃动⽣成。
如此以来rest接⼝维护就只需要关注yaml⽂件,以及UserRestApiHandle 实现类⾥⾯的逻辑就可以了。
1.maven依赖:
<dependencies>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-codegen</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<version>0.9.2</version>
</dependency>
模板解析的时候主要是两种,⼀种根据map的key获取对应的value,⼀种是根据对象的属性名获取相应的值
3.获取yaml⽂件内容(读⽂件)转化成Swagger对象
String info = FileUtils.readFile(filePath);
//将yaml⽂件转化为Swagger对象
Swagger swagger = new SwaggerParser().parse(info);
4.
package ni.jun.yang;
import io.swagger.codegen.ClientOptInput;
import io.swagger.codegen.ClientOpts;
import io.swagger.models.Swagger;
import io.swagger.parser.SwaggerParser;
import ni.jun.yang.ApiCodegen;
import ni.jun.yang.JavaServiceCodegen;
import ni.jun.yang.Util.FileUtils;
import java.io.*;
public class SwaggerTest
{
public void Test(String filePath) throws IOException {
String info = FileUtils.readFile(filePath);
//将yaml⽂件转化为Swagger对象
Swagger swagger = new SwaggerParser().parse(info);
//JavaServiceCodegen继承JavaClientCodegen(存放类的信息,类型对应["integer", "Integer"]表等等),⽤于扩展⼀些⾃定义功能 JavaServiceCodegen serviceCodegen = new JavaServiceCodegen();
ClientOptInput input = new ClientOptInput().opts(new ClientOpts()).swagger(swagger);
input.setConfig(serviceCodegen);
ApiCodegen apiCodegen = new ApiCodegen();
apiCodegen.opts(input).generate();
}
}
import io.swagger.codegen.*;
import nguages.JavaClientCodegen;
public class JavaServiceCodegen extends JavaClientCodegen
{
public JavaServiceCodegen()
{
apiPackage = "ni.jun.yang.api";
modelPackage = "ni.jun.yang.api.bean";
modelTemplateFiles.put("bean.mustache", ".java");
apiTemplateFiles.put("servicerest.mustache", ".java");
}
}
5.组装yaml信息解析模板⽂件,⽣成各类⽂件
package ni.jun.yang;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import io.swagger.codegen.DefaultGenerator;
import io.swagger.models.Path;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.parameters.PathParameter;
import io.swagger.models.properties.Property;
import io.swagger.models.properties.RefProperty;
import ni.jun.yang.Util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ApiCodegen extends DefaultGenerator
{
public List<File> generate() {
List <Map<String,Object>> infoList = new ArrayList<>();
List <Map<String,String>> importList = new ArrayList<>();
Map<String,Path> pathMap = swagger.getPaths();
Info info = new Info();
info.apiPackage = config.apiPackage();
info.modelPackage = config.modelPackage();
info.basePath = swagger.getBasePath();
info.className = swagger.getTags().get(0).getName();
for (Map.Entry<String,Path> entry : pathMap.entrySet())
{
Map<String,Object> infoMap = new HashMap<>();
infoMap.put("urlName", entry.getKey());
Path path = entry.getValue();
changeType(path,infoMap,importList);
infoMap.put("path",path);
infoList.add(infoMap);
}
List = infoList;
info.importList = importList;
String outputFilePath = "src/main/java/ni/jun/yang/api/" + info.className + ".java";
String templateFilePath = "src/main/resources/servicerest.mustache";
String templateFileInfo = "";
try {
//获取模板信息
templateFileInfo = FileUtils.readFile(templateFilePath);
//⽣成模板
Template template = piler().compile(templateFileInfo);
//解析模板
String result = template.execute(info);
//⽣成Controller⽂件
FileUtils.writeFile(result, outputFilePath);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private void changeType(Path path, Map<String,Object> infoMap, List <Map<String,String>> importList)
{
List<Parameter> parameterList;
Map<String, String> typeMap = config.typeMapping();
if (path.getGet() != null)
{
infoMap.put("hasGet", true);
parameterList = path.getGet().getParameters();
for (Parameter parameter : parameterList)
{
PathParameter pathParameter = (PathParameter)parameter;
pathParameter.setType(typeMap.get(pathParameter.getType()));
}
Property property = path.getGet().getResponses().get("200").getSchema();
if (property != null)
{
RefProperty refProperty = (RefProperty)property;
infoMap.put("responseType", refProperty.getSimpleRef());
Map<String,String> map = new HashMap<>();
map.put("import",config.modelPackage() + "." + refProperty.getSimpleRef());
importList.add(map);
}
}
//TODO 其他⼏种请求 put,post,delete...
}
class Info
{
public String apiPackage;
public String modelPackage;
public String basePath;
public String className;
public List <Map<String,String>> importList;
public List <Map<String,Object>> infoList;
}
}
6.mustcahe模板⽂件:
package {{apiPackage}};
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
{{#importList}}
import {{{import}}};
{{/importList}}
@RestController
public class {{className}}
{
//接⼝注⼊,逻辑均在实现类中实现
{{className}}Handle handle;
{{#infoList}}
{{#hasGet}}
@RequestMapping(value = "{{urlName}}",method = RequestMethod.GET)
public {{responseType}} {{path.get.operationId}}(HttpServletRequest request{{#path.get.parameters}}, @PathVariable {{type}} {{name}}{{/path.get.parameters}}) { //TODO
return handle.{{path.get.operationId}}(request{{#path.get.parameters}}, {{name}}{{/path.get.parameters}});
}
{{/hasGet}}
{{/infoList}}
}
7.总结:使⽤Swagger结合mustache模板⽣成后台接⼝代码、以及前后台建模代码⼤致流程就这样,这⾥只贴出了⽣成Controller的相关代码,⽣成前后台模型也是根据⾃⼰的需求来重新组装yaml解析之后的definitions信息即可。
重点是要知道模板解析的时候两种获取值的⽅式:通过类属性获取和根据key获取value,就可以根据⾃⼰需求来组装传⼊模板解析时候对象。
8.swaager yaml⽂件中⾃带的标签可能不能满⾜我们的需求,我们需要扩展⼀些标签,扩展标签要以x-开头,这些信息会放⼊到swagger对象的vendorExtensions属性下。
如 x-abc: aaa。