经常开发表格,是不是已经被手写Ant-Design Table的Columns整烦了?

尤其是ToB项目,表格经常动不动就几十列。每次照着后端给的接口文档一个个配置,太头疼了,主要是有时还会粘错就尴尬了。

那有没有办法能自动生成columns配置呢?

当然可以。

目前后端的接口文档一般是使用Swagger来生成的,Swagger是基于OpenAPI规范的一种实现。(OpenAPI规范是一种描述RESTful API的语言无关的格式,它允许开发者定义API的操作、输入和输出参数、错误响应等信息,并提供了一种规范的方式来描述和交互API。)

那么我们只需要解析Swagger的配置就可以反向生成前端代码。

接下来我们就写个CLI工具来生成Table Columns。

平常我们实现一个CLI工具一般都是用Node,今天我们搞点不一样的,用Rust。

开始咯

swagger.json

打开后端用swagger生成的接口文档中的一个接口,一般是下面这样的,可以看到其json配置文件,如下图:

swagger: 2.0表明了这个文档使用的swagger版本,不同版本json配置结构会不同。

paths这里key是接口地址。

可以看到当前接口是“/api/operations/cate/rhythmTableList”。

顺着往下看,“post.responses.200.schema.originalRef”,这就是我们要找的,这个接口对应的返回值定义。

definitions拿到上面的返回值定义,就可以在“definitions”里找到对应的值。

这里是“definitions.ResponseResult«List«CateInsightRhythmListVO»».properties.data.items.originalRef”

通过他就可找到返回的实体类定义CateInsightRhythmListVO

CateInsightRhythmListVO这里就是我们生成Table Columns需要的字段定义了。

CLI

接下来制作命令行工具

起初我使用的是commander-rust,感觉用起来更符合直觉,全程采用macros定义即可。

但到发布的时候才发现,Rust依赖必须有一个确定的版本,commander-rust目前使用的是分支解析。。。

最后还是换了clap

clap的定义就要繁琐些,如下:

#[derive(Parser)]
#[command(author, version)]
#[command(about = "swagger_to - Generate code based on swagger.json")]
struct Cli {
#[command(subcommand)]
command: Option,
} #[derive(Subcommand)]
enum Commands {
/// Generate table columns for ant-design
Columns(JSON),
} #[derive(Args)]
struct JSON {
/// path/to/swagger.json
path: Option,
}

这里使用#[command(subcommand)]#[derive(Subcommand)]来定义columns子命令

使用#[derive(Args)]定义了path参数,用来让用户输入swagger.json的路径

实现columns子命令

columns命令实现的工作主要是下面几步:

  1. 读取用户输入的swagger.json

  2. 解析swager.json

  3. 生成ant-design table columns

  4. 生成对应Typescript类型定义

读取用户输入的swagger.json

这里用到了一个crate,serde_json, 他可以将swagger.json转换为对象。

let file = File::open(json).expect("File should open");
let swagger_json: Value = serde_json::from_reader(file).expect("File should be proper JSON");

解析swager.json

有了swagger_json对象,我们就可以按照OpenAPI的结构来解析它。

/// openapi.rs

pub fn parse_openapi(swagger_json: Value) -> Vec {
let paths = swagger_json["paths"].as_object().unwrap();
let apis = paths
.iter()
.map(|(path, path_value)| {
let post = path_value["post"].as_object().unwrap();
let responses = post["responses"].as_object().unwrap();
let response = responses["200"].as_object().unwrap();
let schema = response["schema"].as_object().unwrap();
let original_ref = schema["originalRef"].as_str().unwrap();
let data = swagger_json["definitions"][original_ref]["properties"]["data"]
.as_object()
.unwrap();
let items = data["items"].as_object().unwrap();
let original_ref = items["originalRef"].as_str().unwrap();
let properties = swagger_json["definitions"][original_ref]["properties"]
.as_object()
.unwrap();
let response = properties
.iter()
.map(|(key, value)| {
let data_type = value["type"].as_str().unwrap();
let description = value["description"].as_str().unwrap();
ResponseDataItem {
key: key.to_string(),
data_type: data_type.to_string(),
description: description.to_string(),
}
})
.collect();
Api {
path: path.to_string(),
model_name: original_ref.to_string(),
response: response,
}
})
.collect();
return apis;
}

这里我写了一个parse_openapi()方法,用来将swagger.json解析成下面这种形式:

[
{
path: 'xxx',
model_name: 'xxx',
response: [
{
key: '字段key',
data_type: 'number',
description: '字段名'
}
]
}
]

对应的Rust结构定义是这样的:

pub struct ResponseDataItem {
pub key: String,
pub data_type: String,
pub description: String,
} pub struct Api {
pub path: String,
pub model_name: String,
pub response: Vec<ResponseDataItem>,
}

生成ant-design table columns

有了OpenAPI对象就可以生成Table Column了,这里写了个generate_columns()方法:

/// generator.rs

pub fn generate_columns(apis: &mut Vec) -> String {
let mut output_text = String::new();
output_text.push_str("import type { ColumnsType } from 'antd'\n");
output_text.push_str("import type * as Types from './types'\n");
output_text.push_str("import * as utils from './utils'\n\n"); for api in apis {
let api_name = api.path.split('/').last().unwrap();
output_text.push_str(
&format!(
"export const {}Columns: ColumnsType = [\n",
api_name,
api.model_name
)
);
for data_item in api.response.clone() {
output_text.push_str(
&format!(
" {{\n title: '{}',\n key: '{}',\n dataIndex: '{}',\n {}\n }},\n",
data_item.description,
data_item.key,
data_item.key,
get_column_render(data_item.clone())
)
);
}
output_text.push_str("]\n");
} return output_text;
}

这里主要就是采用字符串模版的形式,将OpenAPI对象遍历生成ts代码。

生成对应Typescript类型定义

Table Columns的类型使用generate_types()来生成,原理和生成columns一样,采用字符串模版:

/// generator.rs

pub fn generate_types(apis: &mut Vec) -> String {
let mut output_text = String::new(); for api in apis {
let api_name = api.path.split('/').last().unwrap();
output_text.push_str(
&format!(
"export type {} = {{\n",
Some(api.model_name.clone()).unwrap_or(api_name.to_string())
)
);
for data_item in api.response.clone() {
output_text.push_str(&format!(" {}: {},\n", data_item.key, data_item.data_type));
}
output_text.push_str("}\n\n");
} return output_text;
}

main.rs

然后我们在main.rs中分别调用上面这两个方法即可

/// main.rs

let mut apis = parse_openapi(swagger_json);
let columns = generator::generate_columns(&mut apis);
let mut columns_ts = File::create("columns.ts").unwrap();
write!(columns_ts, "{}", columns).expect("Failed to write to output file");
let types = generator::generate_types(&mut apis);
let mut types_ts = File::create("types.ts").unwrap();
write!(types_ts, "{}", types).expect("Failed to write to output file");

对于columns和types分别生成两个文件,columns.ts和types.ts。

!这里有一点需要注意

当时开发的时候对Rust理解不是很深,起初拿到parse_openapi返回的apis我是直接分别传给generate_columns(apis)和generate_types(apis)的。但编译的时候报错了:

这对于js很常见的操作竟然在Rust中报错了。原来Rust所谓不依赖运行时垃圾回收而管理变量分配引用的特点就体现在这里。

我就又回去读了遍Rust教程里的“引用和借用”那篇,算是搞懂了。这里实际上是Rust变量所有权、引用和借用的问题。读完了自然你也懂了。

看看效果

安装

cargo install swagger_to

使用

swagger_to columns path/to/swagger.json

会在swagger.json所在同级目录生成三个文件:

columns.tsant-design table columns的定义

types.tscolumns对应的类型定义

utils.tscolumn中render对number类型的字段添加了格式化工具

Enjoy

作者:京东零售 于弘达

来源:京东云开发者社区

用 Rust 生成 Ant-Design Table Columns的更多相关文章

  1. Ant Design Table 如何动态自定义?Ant Popover 遮挡?

    项目场景: 基于electron + Vue + node.js + express + mysql + evanpatchouli-mysql + Ant-Design-Vue,编写一款属于自己的轻 ...

  2. ant design Table合并单元格合并单元格怎么用?

    1.ant design table合并单元格怎么用?

  3. 2017.11.6 - ant design table等组件的使用,以及 chrome 中 network 的使用

    一.今日主要任务 悉尼小程序后台管理开发: 景点管理页面: 获取已有数据列表,选取部分数据呈现在表格中,根据景点名称.分类过滤出对应的景点.   二.难点 1. 项目技术选取: ant design. ...

  4. ant design table column 设置width不生效解决方案

    当td里的内容超出了width的范围时,会出现width不固定,也就是width不生效 解决方案: 设置scroll的width等于所有列宽之和(scroll={{x: 100%}})

  5. ant design table td 文字显示过长添加省略号、ant 文字过长时添加tootip提示

    方法1: overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit ...

  6. 同时使用 Ant Design of React 中 Mention 和 Form

    使用场景,在一个列表中,点击每一行会弹出一个表单,通过修改表单数据并提交来修改这一行的数据,其中某个数据的填写需要通过Mention实现动态提示及自动补全的功能. 具体效果为: 遇到的问题: 1.希望 ...

  7. Ant Design项目记录和CSS3的总结和Es6的基本总结

    这里主要是介绍自己运用ANT框架的一些小总结,以前写到word里,现在要慢慢传上来, 辅助生殖项目总结:从每个组件的运用的方法和问题来总结项目. 1.项目介绍 辅助生殖项目主要运用的是Ant.desi ...

  8. 使用ant design pro搭建项目

    脚手架搭建 git clone --depth=1 https://github.com/ant-design/ant-design-pro.git my-project 然后 cd my-proje ...

  9. Ant Design 学习记录

    遇到的问题: 点击列表中的一个字段 , 显示出一条指定id(其他筛选条件的)数据 解决这个问题之前,要先了解 Antd的 Table中的  Column  列描述数据对象,是 columns 中的一项 ...

  10. Ant Design Pro的dva-loading

    loading为dva的插件,全局可用,它里面维护了一些布尔值,用于控制loading动画效果的显示与隐藏,通过@connect()来注入使用 官网介绍如下: https://dvajs.com/ 在 ...

随机推荐

  1. 数据分析01-(numpy概述及使用)

    数据分析-01 数据分析 numpy numpy概述 numpy`历史` numpy的核心:多维数组 numpy基础 ndarray数组 内存中的ndarray对象 ndarray数组对象的特点 nd ...

  2. [OpenCV-Python] 5 视频

    文章目录 OpenCV-Python: II OpenCV 中的 Gui 特性 5 视频 5.1 用摄像头捕获视频 5.2 从文件中播放视频 5.3 保存视频 OpenCV-Python: II Op ...

  3. Android JetPack~LiveData(二) 数据倒灌问题

    Android数据绑定技术一,企业级开发 Android数据绑定技术二,企业级开发 Android  JetPack~ DataBinding(数据绑定)(一)    集成与使用 Android  J ...

  4. 2021-03-27:给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。输入:head = 1→2→3→4→5, k = 2,输出:4→5→1→2→3。

    2021-03-27:给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置.输入:head = 1→2→3→4→5, k = 2,输出:4→5→1→2→3. 福大大 答案20 ...

  5. 2021-05-01:给定一个有序数组arr,代表坐落在X轴上的点。给定一个正数K,代表绳子的长度。返回绳子最多压中几个点?即使绳子边缘处盖住点也算盖住。

    2021-05-01:给定一个有序数组arr,代表坐落在X轴上的点.给定一个正数K,代表绳子的长度.返回绳子最多压中几个点?即使绳子边缘处盖住点也算盖住. 福大大 答案2021-05-01: 滑动窗口 ...

  6. 2022-01-13:K 个不同整数的子数组。 给定一个正整数数组 A,如果 A 的某个子数组中不同整数的个数恰好为 K,则称 A 的这个连续、不一定不同的子数组为好子数组。 (例如,[1,2,3,1

    2022-01-13:K 个不同整数的子数组. 给定一个正整数数组 A,如果 A 的某个子数组中不同整数的个数恰好为 K,则称 A 的这个连续.不一定不同的子数组为好子数组. (例如,[1,2,3,1 ...

  7. 在树莓派上使用numpy实现简单的神经网络推理,pytorch在服务器或PC上训练好模型保存成numpy格式的数据,推理在树莓派上加载模型

    这几天又在玩树莓派,先是搞了个物联网,又在尝试在树莓派上搞一些简单的神经网络,这次搞得是mlp识别mnist手写数字识别 训练代码在电脑上,cpu就能训练,很快的: 1 import torch 2 ...

  8. 2023最新IntellJ IDEA诺依SpringCloud开发部署文档(保姆级别)

    目录 若依RuoYi v3.6.2部署文档 一.环境构建 二.模块描述 三.部署后端 1.下载到本地. 2.MySQL导入数据. 3.Nacos修改 (1)保证本地Nacos下载安装成功,修改本地Na ...

  9. Python 安装教程,新手入门(超详细)含Pycharm开发环境安装教程

    目录 一.Python介绍 二.Python安装教程 (一)Python的下载 (二)Python的安装 三.Pycharm开发工具的安装 (一)Pycharm介绍 (二)Pycharm的下载 (三) ...

  10. Hive执行计划之什么是hiveSQL向量化模式及优化详解

    Hive开启向量化模式也是hiveSQL优化方法中的一种,可以提升hive查询速率,也叫hive矢量化. 问题1:那么什么是hive向量化模式呢? 问题2:hive向量化什么情况下可以被使用,或者说它 ...