api_ddlparse_guide.md 13 KB

DDL解析接口 - 前端开发指南

接口概述

/api/bd/ddlparse 接口用于解析上传的文件,从中提取数据表结构定义信息。支持多种文件格式,适用于业务领域创建场景。

接口信息

属性
URL /api/bd/ddlparse
方法 POST
Content-Type multipart/form-data
认证 根据系统配置

支持的文件类型

文件类型 扩展名 说明
SQL文件 .sql DDL建表语句,支持多表
Excel文件 .xlsx, .xls 表格形式的表结构定义
Word文件 .docx 文档形式的表结构定义(暂不支持 .doc 格式)
PDF文件 .pdf PDF格式的表结构定义文档

请求参数

Form Data

参数名 类型 必填 说明
file File 上传的文件,每次只能上传一个文件

响应格式

成功响应

{
  "code": 200,
  "message": "操作成功",
  "data": [
    {
      "table_info": {
        "name_zh": "用户信息表",
        "name_en": "user_info"
      },
      "columns": [
        {
          "name_zh": "用户ID",
          "name_en": "user_id",
          "data_type": "INTEGER",
          "is_primary": "是",
          "comment": "用户唯一标识",
          "nullable": "否"
        },
        {
          "name_zh": "用户名",
          "name_en": "username",
          "data_type": "VARCHAR(50)",
          "is_primary": "否",
          "comment": "用户登录名",
          "nullable": "否"
        }
      ],
      "exist": false
    }
  ]
}

响应字段说明

顶层结构

字段 类型 说明
code number 状态码,200表示成功
message string 操作结果消息
data array 解析出的表结构数组,始终为数组格式

表结构对象 (data 数组元素)

字段 类型 说明
table_info object 表的基本信息
table_info.name_zh string 表的中文名称
table_info.name_en string 表的英文名称
columns array 字段列表
exist boolean 该表在系统中是否已存在

字段对象 (columns 数组元素)

字段 类型 说明
name_zh string 字段中文名称
name_en string 字段英文名称
data_type string 数据类型(如 VARCHAR(50)、INTEGER)
is_primary string 是否主键:"是" 或 "否"
comment string 字段注释/说明
nullable string 是否可为空:"是" 或 "否"

错误响应

{
  "code": 500,
  "message": "错误描述信息",
  "error": "详细错误信息(可选)"
}

常见错误

错误消息 原因
没有找到上传的文件,请上传一个文件 请求中没有包含文件
未选择文件 文件字段为空
不支持的文件类型: .xxx 上传了不支持的文件格式
暂不支持 .doc 格式,请转换为 .docx 格式后重新上传 上传了旧版 Word 格式
未找到有效的数据表定义信息 文件中没有识别到表结构

前端代码示例

Vue 3 + Element Plus

<template>
  <el-upload
    ref="uploadRef"
    :auto-upload="false"
    :limit="1"
    :on-change="handleFileChange"
    :on-exceed="handleExceed"
    accept=".sql,.xlsx,.xls,.docx,.pdf"
  >
    <template #trigger>
      <el-button type="primary">选择文件</el-button>
    </template>
    <el-button 
      type="success" 
      @click="submitUpload"
      :loading="loading"
      style="margin-left: 10px"
    >
      解析文件
    </el-button>
    <template #tip>
      <div class="el-upload__tip">
        支持 .sql、.xlsx、.xls、.docx、.pdf 格式,单次仅支持上传一个文件
      </div>
    </template>
  </el-upload>

  <!-- 解析结果展示 -->
  <div v-if="tableList.length > 0" class="result-section">
    <h3>解析结果(共 {{ tableList.length }} 个表)</h3>
    <el-collapse v-model="activeNames">
      <el-collapse-item 
        v-for="(table, index) in tableList" 
        :key="index"
        :name="index"
      >
        <template #title>
          <span>
            {{ table.table_info.name_zh || table.table_info.name_en }}
            <el-tag v-if="table.exist" type="warning" size="small">已存在</el-tag>
          </span>
        </template>
        <el-table :data="table.columns" stripe>
          <el-table-column prop="name_zh" label="字段中文名" />
          <el-table-column prop="name_en" label="字段英文名" />
          <el-table-column prop="data_type" label="数据类型" />
          <el-table-column prop="is_primary" label="主键" width="80" />
          <el-table-column prop="nullable" label="可空" width="80" />
          <el-table-column prop="comment" label="备注" />
        </el-table>
      </el-collapse-item>
    </el-collapse>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import axios from 'axios'

const uploadRef = ref()
const loading = ref(false)
const currentFile = ref(null)
const tableList = ref([])
const activeNames = ref([0])

const handleFileChange = (file) => {
  currentFile.value = file.raw
}

const handleExceed = () => {
  ElMessage.warning('每次只能上传一个文件')
}

const submitUpload = async () => {
  if (!currentFile.value) {
    ElMessage.warning('请先选择文件')
    return
  }

  const formData = new FormData()
  formData.append('file', currentFile.value)

  loading.value = true
  try {
    const response = await axios.post('/api/bd/ddlparse', formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      }
    })

    if (response.data.code === 200) {
      tableList.value = response.data.data
      ElMessage.success(`解析成功,共识别到 ${tableList.value.length} 个表`)
    } else {
      ElMessage.error(response.data.message || '解析失败')
    }
  } catch (error) {
    ElMessage.error('请求失败:' + (error.message || '未知错误'))
  } finally {
    loading.value = false
  }
}
</script>

<style scoped>
.result-section {
  margin-top: 20px;
}
</style>

React + Ant Design

import React, { useState } from 'react';
import { Upload, Button, message, Collapse, Table, Tag, Space } from 'antd';
import { UploadOutlined, FileSearchOutlined } from '@ant-design/icons';
import type { UploadFile } from 'antd/es/upload/interface';
import axios from 'axios';

interface Column {
  name_zh: string;
  name_en: string;
  data_type: string;
  is_primary: string;
  comment: string;
  nullable: string;
}

interface TableInfo {
  table_info: {
    name_zh: string;
    name_en: string;
  };
  columns: Column[];
  exist: boolean;
}

const DDLParseUpload: React.FC = () => {
  const [fileList, setFileList] = useState<UploadFile[]>([]);
  const [loading, setLoading] = useState(false);
  const [tableList, setTableList] = useState<TableInfo[]>([]);

  const handleUpload = async () => {
    if (fileList.length === 0) {
      message.warning('请先选择文件');
      return;
    }

    const formData = new FormData();
    formData.append('file', fileList[0] as any);

    setLoading(true);
    try {
      const response = await axios.post('/api/bd/ddlparse', formData, {
        headers: { 'Content-Type': 'multipart/form-data' }
      });

      if (response.data.code === 200) {
        setTableList(response.data.data);
        message.success(`解析成功,共识别到 ${response.data.data.length} 个表`);
      } else {
        message.error(response.data.message || '解析失败');
      }
    } catch (error: any) {
      message.error('请求失败:' + (error.message || '未知错误'));
    } finally {
      setLoading(false);
    }
  };

  const columns = [
    { title: '字段中文名', dataIndex: 'name_zh', key: 'name_zh' },
    { title: '字段英文名', dataIndex: 'name_en', key: 'name_en' },
    { title: '数据类型', dataIndex: 'data_type', key: 'data_type' },
    { title: '主键', dataIndex: 'is_primary', key: 'is_primary', width: 80 },
    { title: '可空', dataIndex: 'nullable', key: 'nullable', width: 80 },
    { title: '备注', dataIndex: 'comment', key: 'comment' },
  ];

  return (
    <div>
      <Space>
        <Upload
          fileList={fileList}
          beforeUpload={(file) => {
            setFileList([file]);
            return false;
          }}
          onRemove={() => setFileList([])}
          accept=".sql,.xlsx,.xls,.docx,.pdf"
          maxCount={1}
        >
          <Button icon={<UploadOutlined />}>选择文件</Button>
        </Upload>
        <Button
          type="primary"
          onClick={handleUpload}
          loading={loading}
          icon={<FileSearchOutlined />}
        >
          解析文件
        </Button>
      </Space>
      <p style={{ color: '#999', fontSize: 12, marginTop: 8 }}>
        支持 .sql、.xlsx、.xls、.docx、.pdf 格式
      </p>

      {tableList.length > 0 && (
        <div style={{ marginTop: 20 }}>
          <h3>解析结果(共 {tableList.length} 个表)</h3>
          <Collapse
            items={tableList.map((table, index) => ({
              key: index,
              label: (
                <span>
                  {table.table_info.name_zh || table.table_info.name_en}
                  {table.exist && <Tag color="warning" style={{ marginLeft: 8 }}>已存在</Tag>}
                </span>
              ),
              children: (
                <Table
                  dataSource={table.columns}
                  columns={columns}
                  rowKey="name_en"
                  size="small"
                  pagination={false}
                />
              ),
            }))}
            defaultActiveKey={[0]}
          />
        </div>
      )}
    </div>
  );
};

export default DDLParseUpload;

原生 JavaScript (Fetch API)

async function parseDDLFile(file) {
  const formData = new FormData();
  formData.append('file', file);

  try {
    const response = await fetch('/api/bd/ddlparse', {
      method: 'POST',
      body: formData
    });

    const result = await response.json();

    if (result.code === 200) {
      console.log('解析成功,表数量:', result.data.length);
      return result.data;
    } else {
      throw new Error(result.message);
    }
  } catch (error) {
    console.error('解析失败:', error);
    throw error;
  }
}

// 使用示例
document.getElementById('fileInput').addEventListener('change', async (e) => {
  const file = e.target.files[0];
  if (!file) return;

  try {
    const tables = await parseDDLFile(file);
    // 处理解析结果
    tables.forEach(table => {
      console.log('表名:', table.table_info.name_zh);
      console.log('字段数:', table.columns.length);
      console.log('是否已存在:', table.exist);
    });
  } catch (error) {
    alert('解析失败: ' + error.message);
  }
});

文件格式建议

SQL 文件

标准的 DDL 建表语句,支持多表:

CREATE TABLE user_info (
    user_id INT PRIMARY KEY COMMENT '用户ID',
    username VARCHAR(50) NOT NULL COMMENT '用户名',
    email VARCHAR(100) COMMENT '邮箱地址'
);

CREATE TABLE order_info (
    order_id BIGINT PRIMARY KEY COMMENT '订单ID',
    user_id INT NOT NULL COMMENT '用户ID',
    total_amount DECIMAL(10,2) COMMENT '订单金额'
);

Excel 文件

建议使用表格形式,包含以下列:

字段英文名 字段中文名 数据类型 是否主键 是否可空 备注
user_id 用户ID INTEGER 用户唯一标识
username 用户名 VARCHAR(50) 登录名

Word 文件

文档中包含表格形式的字段定义,系统会自动识别文档中的表格并解析。

PDF 文件

PDF 中包含的表结构定义文本或表格,系统会提取文本和表格内容进行解析。

注意事项

  1. 文件大小限制:建议单个文件不超过 10MB
  2. 编码格式:SQL 文件建议使用 UTF-8 编码
  3. 单次上传:每次请求只能上传一个文件
  4. 解析时间:由于使用 LLM 进行智能解析,复杂文档可能需要几秒钟
  5. exist 字段:表示该表名是否在系统的业务领域中已存在,用于提示用户避免重复创建
  6. Word 格式:仅支持 .docx 格式,旧版 .doc 格式需要转换后上传

更新日志

版本 日期 更新内容
v1.1.0 2025-12-26 新增 Excel、Word、PDF 文件支持
v1.0.0 - 初始版本,仅支持 SQL 文件