之前项目中使用的的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模板生成后台接口代码、以及前后台建模代码的更多相关文章

  1. MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

    前言 经过前面EF的<第一篇>与<第二篇>,我们的数据层功能已经较为完善了,但有不少代码相似度较高,比如负责实体映射的 EntityConfiguration,负责仓储操作的I ...

  2. Swagger+Spring mvc生成Restful接口文档

    简介 Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参数和模型紧密集 ...

  3. [转]MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

    本文转自:http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.html 〇.目录 一.前言 二.工具准备 三.T4代码生成预热 (一) 单文件生成:Hello ...

  4. 【VS外接程序】利用T4模板生成模块代码

    引言 记得第一次做asp.net mvc项目时,可以用model直接生成Html的增删改查页面, 没什么特殊要求都可以不用修改直接用了, 觉得很神奇,效率太高了.后来在做客户端开发时,发现很多模块都是 ...

  5. [开源] FreeSql.AdminLTE.Tools 根据实体类生成后台管理代码

    前言 FreeSql 发布至今已经有9个月,功能渐渐完善,自身的生态也逐步形成,早在几个月前写过一篇文章<ORM 开发环境之利器:MVC 中间件 FreeSql.AdminLTE>,您可以 ...

  6. spring boot使用swagger生成api接口文档

    前言 在之前的文章中,使用mybatis-plus生成了对应的包,在此基础上,我们针对项目的api接口,添加swagger配置和注解,生成swagger接口文档 具体可以查看本站spring boot ...

  7. CSharpGL(12)用T4模板生成CSSL及其renderer代码

    CSharpGL(12)用T4模板生成CSSL及其renderer代码 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立 ...

  8. 使用 T4 文本模板生成设计时代码

      使用设计时 T4 文本模板,您可以在 Visual Studio 项目中生成程序代码和其他文件. 通常,您编写一些模板,以便它们根据来自模型的数据来改变所生成的代码. 模型是包含有关应用程序要求的 ...

  9. T4模板生成代码。 数据实体层与数据仓储层。备注

    文件生成模板:TempleteManager.ttinclude <#@ assembly name="System.Core" #><#@ assembly n ...

随机推荐

  1. android 自定义Button,抛弃写shape文件

      标签: android 控件  自定义 2017年05月27日 17:52:13 611人阅读 评论(0) 收藏 举报 分类: 自定义View(2) 作者同类文章 X 版权声明:本文为博主原创文章 ...

  2. qss qt按钮自定义

  3. ant安装报错:ANT_HOME is set incorrectly or ant could not be located. Please set ANT_HOME.

    后来发现问题原因是没有设置classpath,或者是\的原因: 正确配置如下:  ANT_HOME:D:\ant\apache-ant-1.10.5 CLASSPATH: %ANT_HOME%\lib ...

  4. 安装VC6.0安装步骤及心得体会

    一.安装步骤: 1.打开网站https://pan.baidu.com/s/nxee/AD ,输入提取密码:wdhk. 2.登录微信账号,将软件下载到D盘. 3.鼠标右键点击VC6.0快捷方式,选择“ ...

  5. shiro使用redis作为缓存,出现要清除缓存时报错 java.lang.Exception: Failed to deserialize at org.crazycake.shiro.SerializeUtils.deserialize(SerializeUtils.java:41) ~[shiro-redis-2.4.2.1-RELEASE.jar:na]

    shiro使用redis作为缓存,出现要清除缓存时报错 java.lang.Exception: Failed to deserialize at org.crazycake.shiro.Serial ...

  6. 【托业】【跨栏】TEST05

    22 23 21. 22 23 24 25 REVIEW TEST05

  7. 2019春第八周作业Compile Summarize

    这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 在这里 我在这个课程的目标是 能更加进一步的够熟练掌握指针的用法 这个作业在那个具体方面帮助我实现目标 指针对于高阶题目的做法 参考文献与 ...

  8. tesseract库

    1.简介 # -*-coding:utf8 -*- #图形验证码识别技术 ''' 阻碍我们爬虫的,有时候是在登录或者请求一些数据时候的图形验证码.因此这里我们讲解 一种能将图片翻译成文字的技术.将图片 ...

  9. for循环的beak continue用法

    continue跳出该循环, for循环后面的都要执行.break直接中段循环 后面不执行了

  10. mipush ionic3 线上push

    <dict> <key>aps-environment</key> <string>production</string> </dic ...