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: "http://www.apache.org/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 ni.jun.yang.api.bean.User; @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>
2.mustache模板语法一搜一大把:https://www.cnblogs.com/DF-fzh/p/5979093.html
模板解析的时候主要是两种,一种根据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 io.swagger.codegen.languages.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);
}
info.infoList = 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 = Mustache.compiler().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,就可以根据自己需求来组装传入模板解析时候对象。
最终要使用这些代码最好的还是做成maven插件(https://www.cnblogs.com/wangxinblog/p/8654400.html),编译即可生成相关的jar包。
8.swaager yaml文件中自带的标签可能不能满足我们的需求,我们需要扩展一些标签,扩展标签要以x-开头,这些信息会放入到swagger对象的vendorExtensions属性下。如 x-abc: aaa
Swagger结合mustache模板生成后台接口代码、以及前后台建模代码的更多相关文章
- MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码
前言 经过前面EF的<第一篇>与<第二篇>,我们的数据层功能已经较为完善了,但有不少代码相似度较高,比如负责实体映射的 EntityConfiguration,负责仓储操作的I ...
- Swagger+Spring mvc生成Restful接口文档
简介 Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参数和模型紧密集 ...
- [转]MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码
本文转自:http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.html 〇.目录 一.前言 二.工具准备 三.T4代码生成预热 (一) 单文件生成:Hello ...
- 【VS外接程序】利用T4模板生成模块代码
引言 记得第一次做asp.net mvc项目时,可以用model直接生成Html的增删改查页面, 没什么特殊要求都可以不用修改直接用了, 觉得很神奇,效率太高了.后来在做客户端开发时,发现很多模块都是 ...
- [开源] FreeSql.AdminLTE.Tools 根据实体类生成后台管理代码
前言 FreeSql 发布至今已经有9个月,功能渐渐完善,自身的生态也逐步形成,早在几个月前写过一篇文章<ORM 开发环境之利器:MVC 中间件 FreeSql.AdminLTE>,您可以 ...
- spring boot使用swagger生成api接口文档
前言 在之前的文章中,使用mybatis-plus生成了对应的包,在此基础上,我们针对项目的api接口,添加swagger配置和注解,生成swagger接口文档 具体可以查看本站spring boot ...
- CSharpGL(12)用T4模板生成CSSL及其renderer代码
CSharpGL(12)用T4模板生成CSSL及其renderer代码 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立 ...
- 使用 T4 文本模板生成设计时代码
使用设计时 T4 文本模板,您可以在 Visual Studio 项目中生成程序代码和其他文件. 通常,您编写一些模板,以便它们根据来自模型的数据来改变所生成的代码. 模型是包含有关应用程序要求的 ...
- T4模板生成代码。 数据实体层与数据仓储层。备注
文件生成模板:TempleteManager.ttinclude <#@ assembly name="System.Core" #><#@ assembly n ...
随机推荐
- 9. http协议_响应状态码_页面渲染流程_路由_中间件
1. http协议 超文本传输协议 协议详细规定了 浏览器 和 万维网服务器 之间互相通信的规则 客户端与服务端通信时传输的内容我们称之为报文(请求报文.响应报文) 常见的发送 get 请求方式 在浏 ...
- 26 Arcpy跳坑系列——ExportToPNG
最近在学习Arcpy的时候,还真是遇到了一个磨人的小妖精,我本来是想得到一个透明背景的png图的,根据官方的帮助文档, https://desktop.arcgis.com/zh-cn/arcmap/ ...
- jdbc的入门学习
一.JDBC相关概念介绍 1.1.数据库驱动 这里的驱动的概念和平时听到的那种驱动的概念是一样的,比如平时购买的声卡,网卡直接插到计算机上面是不能用的,必须要安装相应的驱动程序之后才能够使用声卡和网卡 ...
- popwindow+动画
布局: main: <Button android:id="@+id/btn" android:layout_width="match_parent" a ...
- 数学和物理太难?这些 GIF 让你秒懂抽象概念
把科学带回家,给孩子最好的科学教育 觉得数学和物理很抽象很难懂吗?今天我们来分享一组数学和物理相关的动图,让你秒懂抽象概念. 数学动图 △ 从椭圆的一个焦点射出的光线总会通过另一个焦点. △ 真人版. ...
- Django ORM中datetiem数据类型字段无法对比处理办法
在做商城项目中浏览足迹时,我利用浏览商品的ID和浏览的时间保存到browse表中,然后在我的足迹页面根据最近日期进行展示 条件:每天/个商品只能如一次表 后台代码如下: #存储浏览足迹到browse表 ...
- SVG笔记
SVG可缩放矢量图形(Scalable Vector Graphics)是基于可扩展标记语言(XML),用于描述二维矢量图形的一种图形格式.SVG是W3C("World Wide Web C ...
- 【技巧】-NO.123.数据处理技巧
Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...
- 【心得】-NO.114.面试.1 -【To HR And Interviewer】
Style:Mac Series:Java Since:2018-09-10 End:2018-09-10 Total Hours:1 Degree Of Diffculty:5 Degree Of ...
- C++模板的要点
1.函数模板与普通函数的区别: 普通函数可以进行自动类型转化,而函数模板不可以. 举个例子 //函数模板 template<class T> void show(T a,T b){ cou ...