用Rust生成Ant-Design Table Columns | 京东云技术团队
经常开发表格,是不是已经被手写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-designColumns(JSON),
}#[derive(Args)]
struct JSON {/// path/to/swagger.jsonpath: Option,
}
这里使用#[command(subcommand)]和#[derive(Subcommand)]来定义columns子命令
使用#[derive(Args)]定义了path参数,用来让用户输入swagger.json的路径
实现columns子命令
columns命令实现的工作主要是下面几步:
-
读取用户输入的swagger.json
-
解析swager.json
-
生成ant-design table columns
-
生成对应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.rspub 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.rspub 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.rspub 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.rslet 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 | 京东云技术团队
经常开发表格,是不是已经被手写Ant-Design Table的Columns整烦了? 尤其是ToB项目,表格经常动不动就几十列。每次照着后端给的接口文档一个个配置,太头疼了,主要是有时还会粘错就尴尬了。 那有没有办法能自动生成colu…...
java.lang.ClassNotFoundException: sun.misc.BASE64Decoder
有一个新的应用服务,idea启动应用应用服务时,突然报错java.lang.ClassNotFoundException: sun.misc.BASE64Decoder ,然后在网上搜索,说是建议使用apache包,该类新的JRE已经废弃,并从rt.jar包中移除。但是该…...
Unity进阶--对象池数据场景管理器笔记
文章目录 泛型单例类泛型单例类(不带组件版)对象池管理器数据管理器场景管理器 泛型单例类 using System.Collections; using System.Collections.Generic;public abstract class ManagersSingle<T> where T : new() {private static T instance;…...
【Seata】微服务集成seata
文章目录 1、Seata介绍2、Seata架构3、部署TC服务4、微服务集成seata 1、Seata介绍 Seata是 2019 年 1 月份蚂蚁金服和阿里巴巴共同开源的分布式事务解决方案。 官网http://seata.io/ 2、Seata架构 Seata事务管理有三个角色: TC (Transaction Coordinator) - 事务…...
解决react,<img>src使用require方法引入图片不显示问题
{settingList.map(i > (<img src{require(./images/${i.deviceTypeName}.png).default} />))} 解决方法: 再导入的图片后加.default即可 <img src{require(../../images/bg.png).default} alt"" /> 推荐阅读:https://www.cnb…...
从小白到大神之路之学习运维第67天-------Tomcat应用服务 WEB服务
第三阶段基础 时 间:2023年7月25日 参加人:全班人员 内 容: Tomcat应用服务 WEB服务 目录 一、中间件产品介绍 二、Tomcat软件简介 三、Tomcat应用场景 四、安装配置Tomcat 五、配置目录及文件说明 (一)to…...
图解SQL基础知识,小白也能看懂的SQL文章
本文介绍关系数据库的设计思想: 在 SQL 中,一切皆关系。 在计算机龄域有许多伟大的设计理念和思想,例如: 在 Unix 中,一切皆文件。 在面向对象的编程语言中,一切皆对象。 关系数据库同样也有自己的设计…...
自动驾驶感知系统-毫米波雷达
毫米波雷达就是电磁波,雷达通过发射无线电信号并接收反射信号来测定车辆与物体间的距离,其频率通常介于10~300GHz之间。与厘米波导引头相比,毫米波导引头体积小,质量轻,空间分辨率高;与红外、激光、电视等光…...
Esp32_Arduino接入腾讯云笔记
ESP32是一款由乐鑫科技(Espressif Systems)推出的双核、低功耗、集成Wi-Fi和蓝牙的单芯片微控制器。它采用了Tensilica Xtensa LX6高性能处理器,具有大量的GPIO引脚、模数转换器、SPI、I2S、UART、PWM、I2C和SD卡接口等功能,可以满…...
python简单入门
python简单入门 文章目录 python简单入门0. 地址链接1. 官网2.2. 下载地址3. 官方文档 1. 第一章1.1 python解释器1.2 基础语法1.2.1 常见数据类型1.2.2 强制类型转换1.2.3 注释1.2.4 运算符1.2.5 字符串1.2.5.1 字符串的定义1.2.5.2 字符串拼接1.2.5.3 格式化字符串1.2.5.3 精…...
如何快速从csv文件搭建一个简单的神经网络模型(回归)
快速搭建一个简单的神经网络预测模型 采用的数据是kaggle的房价预测数据 涉及的数据文件,提取码为:zxcv #导入相关包 import pandas as pd import numpy as np import torch import torch.nn as nn首先读取数据 trainpd.read_csv("path",enc…...
Pytorch深度学习-----DataLoader的用法
系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用(ToTensor,Normalize,Resize ,Co…...
macOS Ventura 13.5 (22G74) Boot ISO 原版可引导镜像下载
macOS Ventura 13.5 (22G74) Boot ISO 原版可引导镜像下载 本站下载的 macOS 软件包,既可以拖拽到 Applications(应用程序)下直接安装,也可以制作启动 U 盘安装,或者在虚拟机中启动安装。另外也支持在 Windows 和 Lin…...
【机器学习】 奇异值分解 (SVD) 和主成分分析 (PCA)
一、说明 在机器学习 (ML) 中,一些最重要的线性代数概念是奇异值分解 (SVD) 和主成分分析 (PCA)。收集到所有原始数据后,我们如何发现结构?例如,通过过去 6 天…...
如何用logging记录python实验结果?
做python实验有时候需要打印很多信息在控制台(console),但是控制台的信息不方便回顾和保存,故而可以采用logging将信息存储起来。 先新建一个文件message.log代码如下: import logging logging.basicConfig(filename"messa…...
C语言假期作业 DAY 03
目录 题目 一、选择题 1、已知函数的原型是: int fun(char b[10], int *a); ,设定义: char c[10];int d; ,正确的调用语句是( ) 2、请问下列表达式哪些会被编译器禁止【多选】( ) 3、…...
使用serverless实现从oss下载文件并压缩
公司之前开发一个网盘系统, 可以上传文件, 打包压缩下载文件, 但是在处理大文件的时候, 服务器遇到了性能问题, 主要是这个项目是单机部署.......(离谱), 然后带宽只有100M, 现在用户比之前多很多, 然后所有人的压缩下载请求都给到这一台服务器了, 比如多个人下载的时候带宽问…...
从上到下打印二叉树
题目描述 从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。 例如: 给定二叉树: [3,9,20,null,null,15,7], 返回: [3,9,20,15,7] 算法思想 建立一个vector数组ret用来当做返回的结果数组,建立一个队列用来接收二叉树…...
【推荐】排序模型的调优
【推荐】排序模型的调优 排序模型的选择 排序模型常见的训练方式 样本类别不均衡处理尝试 欠拟合 过拟合 其他问题 排序模型的选择 LR,GBDT,LRGBDT,FM/FFM, 深度模型(wide & deep,DeepFM&#x…...
负载均衡安装配置详解
负载均衡(Load Balancing)是一种将网络流量分布到多个服务器上的技术,以提高系统的性能、可靠性和可扩展性。 在负载均衡中,有一个负载均衡器(Load Balancer),它充当了传入请求的前置接收器。当…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
