# 政务表单动态建表?运行时DDL引擎,前端拖完字段后端直接建

政务表单动态建表?运行时DDL引擎,前端拖完字段后端直接建

非科班野生程序员,深耕政务信息化20年。从VC到PB再到Java,自研框架browise也打磨了十几年。最近整理框架代码,发现不少有趣的决策,写出来和大家聊聊。最后感谢豆包、智谱、OpenCode,决策是我做的,代码是我搓的,文字是他们总结的。

场景

政务系统有个典型需求:业务人员在页面上设计表单,拖几个字段上去,点保存,后台就得在数据库里建一张物理表。不是虚拟表、不是JSON存储,是真正的物理表。因为后续要对接报表、对接工作流,没有物理表寸步难行。

而且还得支持 Oracle 和 SQL Server 两种数据库------信创改造期间两个库并行跑。

整体设计

复制代码
前端拖字段 → JSON传到后端 → DDLop(入口)
                                    ↓
                            DDLinterface(接口)
                              ↓           ↓
                    DDL_oracle_impl    DDL_mssql_impl
                         ↓                    ↓
                  拼Oracle DDL          拼MSSQL DDL
                         ↓
               自动生成五级元数据(ea01~ea05)

第一层:DDLop --- 入口控制器

java 复制代码
// DDLop.java
@aoppoint
@bean(id="ddlop")
@responseMapping(key="/ddlop")
public class DDLop {
    
    @property(type="ref", value="ddlimpl_oracle")
    DDLinterface impl ;

    @Trans
    @monitoring
    @responseMapping(key="/createtable")
    @responseType(type=String.class)
    public String createtable(newDataStore<ddlDao> ddlds) throws utilException
    {           
        impl.createtable(ddlds);
        return "创建成功!";
    }

    @Trans
    @monitoring
    @responseMapping(key="/altertable")
    @responseType(type=String.class)
    public String altertable(newDataStore<ddlDao> ddlds) throws utilException
    {
        impl.alerttable(ddlds);
        return "修改成功!";
    }
}

注意 @property(type="ref", value="ddlimpl_oracle")------通过IoC容器注入具体实现。切数据库只改这一行配置,Oracle换成 "ddlimpl_mssql" 就行。

第二层:DDLinterface --- 统一接口

java 复制代码
// DDLinterface.java
public interface DDLinterface {
    public void createtable(newDataStore<ddlDao> ddlds) throws utilException;
    public void alerttable(newDataStore<ddlDao> ddlds) throws utilException;
}

就两个方法:建表、改表。ddlDao 里每个字段有 columnnamedatatypedataleniskeydes 这些属性。

第三层:DDL_oracle_impl --- Oracle建表

建表过程分四步:

第一步:拼 CREATE TABLE

java 复制代码
StringBuffer buffer = new StringBuffer();
buffer.append("create table ");
String tableName = (String) ddlds.getParameter("tablename");
buffer.append(tableName);
buffer.append(" ( \r\n");
for(int i =0;i<ddlds.getRowSet().getPrimary().size();i++)
{
    ddlDao dao = ddlds.getRowSet().getrow(i);
    buffer.append("\t");
    buffer.append(dao.getColumnname());
    buffer.append(" ");
    if("1".equals(dao.getDatatype()))
        buffer.append("varchar2(512)");
    if("2".equals(dao.getDatatype()))
        buffer.append("date");
    if("3".equals(dao.getDatatype()))
        buffer.append("number(18,2)");
    if("4".equals(dao.getDatatype()))
        buffer.append("date");
    if(dao.isIskey())
        buffer.append(" not null");
    if(i < ddlds.getRowSet().getPrimary().size() -1 )
        buffer.append(",");
    buffer.append("  \r\n");
}
buffer.append(" ) \r\n");
DBUtil.SaveDao(DDLMapper.class, "execsql", buffer.toString());

数据类型用编码:"1" 是字符串,"2" 是日期,"3" 是数字,"4" 是日期时间。前端传编码,后端按数据库方言翻译。

第二步:拼主键约束

java 复制代码
buffer = new StringBuffer();
buffer.append("alter table  ");
buffer.append(tableName);
buffer.append(" add constraint ");
buffer.append("PK_"+ tableName + " ");
buffer.append(" primary key ( ");
// ... 遍历标记了iskey的字段
buffer.append(" )");
if(count > 0)
    DBUtil.SaveDao(DDLMapper.class, "execsql", buffer.toString());

第三步:加表注释和字段注释

java 复制代码
String tablesql="comment on table "+tableName + " is '"+ tabledes+"'";
DBUtil.SaveDao(DDLMapper.class, "execsql", tablesql);

for(int i =0;i<ddlds.getRowSet().getPrimary().size();i++)
{
    ddlDao dao = ddlds.getRowSet().getrow(i);
    String sql = "comment on column "+ tableName + "."+ dao.getColumnname() 
                 +" is '" + dao.getDes() +"'";
    DBUtil.SaveDao(DDLMapper.class, "execsql", sql);
}

政务系统表注释是必须的,审计的时候说得清楚每个字段什么含义。

第四步:自动生成五级元数据

这是关键。如果表里有 proc_inst_id_ 字段(说明这张表要挂工作流),就自动生成一套元数据:

java 复制代码
if(isform)
{
    createsql(tableName,tabledes,ddlds);
}

createsql 方法会往 ea01~ea05 五张元数据表里写入记录:

  • ea01:表级定义(表名、表描述)
  • ea02:表别名映射
  • ea03:字段级定义(字段名、类型、排序、注释)
  • ea04:字段分组
  • ea05 :默认查询条件(自动加 proc_inst_id_ 作为关联条件)

有了这五级元数据,前端的列表页、查询条件、表单渲染都可以自动生成,不需要手写一行SQL。

第四层:DDL_mssql_impl --- SQL Server建表

和 Oracle 实现几乎一样,区别只在数据类型映射和注释语法:

java 复制代码
// Oracle: comment on table xxx is 'xxx'
// MSSQL:
String tablesql="execute sp_addextendedproperty 'MS_Description','"+tabledes+
        "','user','dbo','table','"+tableName+"',null,null ";

// 字段注释
String sql = "EXECUTE sp_addextendedproperty 'MS_Description_c', '"+ dao.getDes() +
        "', 'user', 'dbo', 'table', '"+tableName +
        "', 'column', '"+dao.getColumnname() +"'";

SQL Server 用 sp_addextendedproperty 加注释,修改注释的时候先 add,失败了再 update

java 复制代码
try {
    DBUtil.SaveDao(DDLMapper.class, "execsql", sql); 
}
catch(utilException e)
{
    sql = "EXECUTE sp_updateextendedproperty  'MS_Description_c', '"+ dao.getDes() +
            "', 'user', 'dbo', 'table', '"+tableName +
            "', 'column', '"+dao.getColumnname() +"'";
    DBUtil.SaveDao(DDLMapper.class, "execsql", sql); 
}

这种"先试增再改"的方式很务实,比先查后判断省一轮数据库交互。

改表支持什么

alerttable 方法支持三种操作:

  1. 加字段 :遍历 primary 列表,isInsert() 为 true 的拼 ALTER TABLE ADD
  2. 删字段 :遍历 delete 列表,isModefiy() 为 true 的拼 ALTER TABLE DROP COLUMN
  3. 改注释:重新写入所有字段注释

注意字段状态复用了 BaseDao 的 _t 状态机,新增=1,修改=3,删除=4。

小结

整个 DDL 引擎就三个类加一个接口,加起来不到700行代码,但解决了政务系统里"表单设计器拖字段后端自动建表"的完整链路。Oracle 和 SQL Server 切换只改一行IoC配置。五级元数据自动生成,前端列表查询表单全自动渲染。


做过动态建表的同学来聊聊,你们是怎么处理的?评论区见。

标签:#Java #DDL #动态建表 #Oracle #SQLServer #政务信息化 #自研框架

相关推荐
我登哥MVP2 小时前
【Spring6笔记】 - 13 - 面向切面编程(AOP)
java·开发语言·spring boot·笔记·spring·aop
San30.2 小时前
前端渲染:从 CSR、SSR 到同构与手写 Vite+React SSR 实践
前端·react.js·前端框架
宸津-代码粉碎机2 小时前
Spring Boot 4.0 进阶实战+源码解析系列(持续更新)—— 从落地到源码,搞定面试与工作
java·人工智能·spring boot·后端·python·面试
三声三视2 小时前
React 19 正式发布!17 个新特性深度解析与迁移指南(2026 实战版)
前端·javascript·reactjs·react
沐雪轻挽萤2 小时前
2. C++17新特性-结构化绑定 (Structured Bindings)
java·开发语言·c++
java1234_小锋2 小时前
Java高频面试题:Kafka的消费消息是如何传递的?
java·开发语言·mybatis
滴滴答答哒2 小时前
c#将平铺列表转换为树形结构(支持孤儿节点作为独立根节点)
java·前端·c#
雨季mo浅忆2 小时前
第四项目梳理
前端·面试·vue2
a1117762 小时前
三维地图可视化 ThreeJS vue 开源项目
前端·javascript·vue.js