内网 MySQL 表结构一键导出 Word 文档:直连 + Agent 双模式实战

一、功能简述

在线工具站(onltool.site)有一个"MySQL 表结构文档"小工具:输入数据库连接信息,点击导出,下载一个排版整齐的 Word 设计文档。

体验:

复制代码
输入 IP / 端口 / 用户名 / 密码 / 数据库名 → 点导出 → 浏览器下载 doc 文件

文档包含每张表的表名、注释、字段序号、字段名、类型、是否必填、备注,用表格清晰展示。


二、技术选型:为什么用 FreeMarker 而不是 POI?

方案 复杂度 排版控制 文件体积
Apache POI 编程式生成 精确
FreeMarker 模板填充 灵活
HTML 另存为 .doc

选择 FreeMarker:用 Word XML 模板(.ftl),表结构数据填充进去,生成的 .doc 文件排版精确、体积小、兼容 WPS 和 Office。


三、直连模式的实现

3.1 后端采集数据

java 复制代码
// 1. 查 information_schema 获取所有表
SELECT TABLE_NAME, TABLE_COMMENT 
FROM information_schema.TABLES 
WHERE TABLE_SCHEMA = ? 
ORDER BY TABLE_NAME

// 2. 每张表查字段结构
SHOW FULL COLUMNS FROM `table_name`

3.2 构建数据模型

java 复制代码
List<Map<String, Object>> tableList = new ArrayList<>();
for (表) {
    Map<String, Object> tableMap = new HashMap<>();
    tableMap.put("name", "users(用户表)");  // 表名+注释
    
    List<Map<String, String>> structures = new ArrayList<>();
    for (字段) {
        Map<String, String> col = new LinkedHashMap<>();
        col.put("code", "1");          // 序号
        col.put("field", "id");        // 字段名
        col.put("type", "int(11)");    // 类型
        col.put("isNull", "是");        // 是否必填
        col.put("comment", "主键ID");   // 备注
        structures.add(col);
    }
    tableMap.put("structure", structures);
    tableList.add(tableMap);
}

3.3 FreeMarker 模板渲染

使用 6000 行的 Word XML 模板(tables.ftl),包含字体、页边距、标题样式、表格边框等全部排版信息。数据填充只占模板的极小部分:

xml 复制代码
<#list tables as table>
  <w:p><w:r><w:t>${table.name}</w:t></w:r></w:p>
  <#list table.structure as col>
    <w:tr>
      <w:tc><w:p><w:r><w:t>${col.code}</w:t></w:r></w:p></w:tc>
      <w:tc><w:p><w:r><w:t>${col.field}</w:t></w:r></w:p></w:tc>
      ...
    </w:tr>
  </#list>
</#list>

3.4 返回文件

java 复制代码
ByteArrayOutputStream baos = new ByteArrayOutputStream();
template.process(dataMap, new BufferedWriter(new OutputStreamWriter(baos)));

return ResponseEntity.ok()
    .header("Content-Disposition", "attachment; filename*=UTF-8''数据库_表结构.doc")
    .contentType(MediaType.APPLICATION_OCTET_STREAM)
    .body(baos.toByteArray());

四、Agent 模式:当数据库在内网

云端服务器无法直接连接用户内网的 MySQL。与 SQL 查询工具一样,这里也用 WebSocket + 本地 Agent 隧道。

4.1 第一版:Agent 自己生成 Word(踩坑)

最初让 Agent 连 MySQL、查表结构、生成 HTML 转 Word、base64 回传。问题:

问题 1:样式不一致。 Agent 用的简易 HTML 样式,后端直连用的是 6000 行 XML 模板,两个 Word 文档排版完全不同。

问题 2:消息体过大。 8 张表的 Word 文档 base64 后超过 Spring Boot 默认的 64KB WebSocket 缓冲区上限,服务器直接关闭连接:

复制代码
The decoded text message was too big for the output buffer
and the endpoint does not support partial messages

4.2 第二版:Agent 只采集数据,后端统一渲染

推翻重来,改为:

复制代码
Agent 连 MySQL → 查表结构 → 返回 JSON 数据 → 前端 POST 给后端 → 后端 FreeMarker 渲染 → 下载

Agent 只做数据采集:

python 复制代码
def handle_table_structure(ws, msg):
    conn = pymysql.connect(host=host, port=port, user=user, ...)
    
    # 查所有表
    cursor.execute("SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema...")
    tables = cursor.fetchall()
    
    table_data = []
    for table_name, comment in tables:
        cursor.execute(f"SHOW FULL COLUMNS FROM `{table_name}`")
        columns = cursor.fetchall()
        cols = [{"field": c[0], "type": c[1], "required": ..., "comment": c[8]} for c in columns]
        table_data.append({"name": table_name, "comment": comment, "columns": cols})
    
    send(ws, {"type": "tableStructureResult", "database": database, "tables": table_data})

后端新增 Agent 模式入口:

java 复制代码
@PostMapping("/export")
public ResponseEntity<byte[]> export(@RequestBody Map<String, Object> body) {
    List<Map<String, Object>> tableList = new ArrayList<>();

    // Agent 模式:数据已由 Agent 采集好
    if (body.containsKey("tables")) {
        for (Map<String, Object> t : (List) body.get("tables")) {
            // 构建与直连模式完全相同的数据结构
            tableMap.put("name", displayName);
            tableMap.put("structure", structures);
            tableList.add(tableMap);
        }
        return renderWord(database, tableList);  // 共用 FreeMarker 渲染
    }

    // 直连模式:后端自己连 MySQL
    ...
    return renderWord(database, tableList);
}

前端中继:

javascript 复制代码
case 'tableStructureResult':
  // 收到 Agent 的 JSON 数据 → 发给后端生成 Word
  request({
    url: '/api/pub/table-structure/export',
    method: 'post',
    data: { database: msg.database, tables: msg.tables },
    responseType: 'blob'
  }).then(res => {
    // 触发浏览器下载
    const url = window.URL.createObjectURL(new Blob([res]))
    const a = document.createElement('a')
    a.href = url; a.download = msg.database + '_table_structure.doc'
    a.click()
  })
  break

五、关键坑点

5.1 WebSocket 消息体超限

Spring Boot + Tomcat 默认 WebSocket 文本消息缓冲区 64KB 。数据库表多时,JSON 数据体轻松超标。配置 ServletServerContainerFactoryBean 扩到 50MB:

java 复制代码
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
    ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
    container.setMaxTextMessageBufferSize(50 * 1024 * 1024);  // 50 MB
    container.setMaxSessionIdleTimeout(0L);
    return container;
}

5.2 竞态条件导致结果丢失

Agent 返回 JSON 时,如果浏览器 WebSocket 恰好断开重连,后端 removeBrowser 可能误清掉新连接的 session:

java 复制代码
// 修复:只清理自己的 session
if (pair.browserSession == browserSession) {
    pair.browserSession = null;
}

5.3 样式一致性

Agent 不生成 Word,只回传结构化数据。所有 Word 文档统一走后端 FreeMarker 模板渲染,保证直连和 Agent 两种模式输出的文档排版完全一致。


六、结果展示

小工具页面

导出设计文档截图


七、架构总结

复制代码
直连模式:前端 → 后端(连MySQL + FreeMarker) → Word blob → 下载
Agent模式:前端 → WebSocket → Agent(连MySQL, 回传JSON) → 前端 → 后端(FreeMarker) → Word blob → 下载
                                                              ↑
                                                    两种模式在此汇合

核心设计原则:Agent 只做它擅长的事(穿透内网),Word 生成永远交给后端的同一套 FreeMarker 模板

项目在线地址:https://onltool.site

相关推荐
Bruce_Liuxiaowei2 小时前
基于微步在线威胁情报的公网 IP 攻击迹象监测:threatbook_query 脚本全解析与 BruceSec 平台整合实践
数据库·tcp/ip·安全·网络安全·智能体
码农颜2 小时前
5.6.2 ⾏级锁死锁
数据库·sql·oracle
Am-Chestnuts2 小时前
豆包表格复制到 Word 后错列,先保留 Markdown 再转换
word
ChaHae-In2 小时前
MyBatis动态SQL与MyBatis-Plus高效开发指南
数据库·oracle·mybatis
冰暮流星2 小时前
mysql之分组查询
数据库·mysql
倒流时光三十年3 小时前
PostgreSQL Semi-Join(半连接)通俗讲解
数据库·postgresql
NiceCloud喜云4 小时前
腾讯云国际版云数据库选型:MySQL、Redis 怎么按业务架构来判断
数据库·mysql·腾讯云
ew452184 小时前
MySQL JOIN 关联语法、差异、标准用法、经典坑点汇总
数据库·mysql
Rain的Java大神之路4 小时前
线上接口负载满了如何解决
java·数据库·redis·后端·缓存·面试·架构
DS随心转APP4 小时前
deepseek生成的word怎么下载 AI导出鸭全平台方案技术深度测评
人工智能·ai·chatgpt·word·deepseek·ai导出鸭