# 政务表单动态建表?运行时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 #政务信息化 #自研框架

相关推荐
ting94520009 小时前
Tornado 全栈技术深度指南:从原理到实战
人工智能·python·架构·tornado
云水一下10 小时前
从零开始!VMware安装Fedora Workstation 44桌面系统完整教程
前端
wuminyu11 小时前
专家视角看Java字节码加载与存储指令机制
java·linux·c语言·jvm·c++
小码哥_常11 小时前
Spring Boot:别再重复造轮子,这些内置功能香麻了
后端
小码哥_常11 小时前
安卓黑科技:实现多平台商品详情页一键跳转APP
前端
killerbasd11 小时前
还是迷茫 5.3
前端·react.js·前端框架
皮皮林55111 小时前
OpenFeign 首次调用卡 3 秒?八年老开发扒透 5 个坑,实战优化到 100ms!
后端
不会敲代码112 小时前
TCP/IP 与前端性能:从数据包到首次渲染的底层逻辑
前端·tcp/ip
kyriewen12 小时前
奥特曼借GPT-5.5干杯,而你的Copilot正按Token收钱
前端·github·openai
callJJ12 小时前
Spring Data Redis 两种编程模型详解:同步 vs 响应式
java·spring boot·redis·python·spring