# 政务表单动态建表?运行时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 里每个字段有 columnname、datatype、datalen、iskey、des 这些属性。

第三层: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 #政务信息化 #自研框架

相关推荐
西柚小萌新3 分钟前
【LLM&&AI应用开发 八股文】--4.3.Agent智能体(下)
java·开发语言·数据库
北极有牛6 分钟前
cpp学习笔记--常量指针
java·开发语言·算法
回眸&啤酒鸭7 分钟前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
java资料站13 分钟前
二、Spring AI Alibaba · ChatModel
java·windows·spring
用户693717500138416 分钟前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员19 分钟前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端
姜鱼问生29 分钟前
Linux 日志增量统计:inode + offset 方案(不丢不重)
架构
惜鸟29 分钟前
从源码看 pi 的上下文管理:原始数据永久保留,模型视角按需裁剪
后端
软件工程师_罗小东32 分钟前
我把这套 AI 落地方案,讲成一条任务闭环
架构
小兔子34 分钟前
Python 的 GIL 与 free-threading:3.13 之后「去 GIL」走到哪一步了
前端