从遗留项目提取低代码平台
从遗留项目提取低代码平台:browise 的诞生
文章目录
- 从遗留项目提取低代码平台:browise 的诞生
-
- 引子
- 提取什么?
-
- 1. 元数据驱动 SQL 引擎(ea-component)
- 2. 报表模板引擎(FileUtil.print)
- 3. 32 个前端 UI 组件
- 怎么提取?
-
- 不修改原文
- 保持包名不变
- 砍掉过时的依赖
- 重写而非迁移的模块
- 额外新写的部分
-
- 前端核心层(7 个 TypeScript 文件)
- 通用工具(4 个 Java 文件)
- Demo(含报表接口)
- 最终架构
- 一点经验
引子
我手上有两个项目:
- VedioCall:2004 年起的政务框架,一路从 Struts 1 演进到 Spring Boot
- hnxnb:2017 年基于 VedioCall 的社保系统,72 人月交付 200 人月工作量
两个项目里都跑着一套叫 browise 的自研框架。这套框架没有独立版本号、没有单独的仓库、没有文档——它只是散落在各个项目里的 Java 文件、JSP 标签、JavaScript 脚本。
2024 年,我接到新任务:做一个新项目。业务不同,但底层需求一样——CRUD、报表、工作流、表单。
面前两条路:
- A. 重新选型:Formily / Avue / Amis,然后开始适配
- B. 把 browise 提取出来,变成一个独立平台
我选了 B。不是情怀,是算过账的:
提取成本约 2 周,适配任何一个第三方框架至少 4 周,而且第三方框架不覆盖"元数据 SQL 引擎"和"脏标记 RowSet"这两块最核心的能力。
提取什么?
一个遗留框架散落在项目里,第一步不是写代码,是考古。
翻阅 VedioCall 和 hnxnb,我圈出了必须保留的部分:
1. 元数据驱动 SQL 引擎(ea-component)
这是整个框架最值钱的部分。它做的事情是:
你配置一条 SQL 定义(存数据库表里),引擎自动生成 CRUD + 分页 + 8 种数据库兼容。
比如你配一条查询"SELECT * FROM EMP WHERE NAME = #name#",引擎会:
- 自动解析参数绑定
- 自动处理分页(Oracle 用 rownum,MySQL 用 LIMIT,SQL Server 用 row_number())
- 自动处理加密字段的加解密
- 自动处理敏感字段的脱敏
- 所有 metadata 缓存在 memory 里
这套代码在 VedioCall 里叫 ea-component,结构是三个 Maven 模块:
-
ea-core:引擎内核 -
ea-spring-boot-starter:Spring Boot 自动装配 -
ea-adapter-browise:DataSource 连接提供者
32 个 Java 文件,分布在三个模块中。
2. 报表模板引擎(FileUtil.print)
VedioCall 的 FileUtil.java 有 2805 行,核心是一个叫 print() 的方法。
它的机制是:读一个 Excel 模板文件,识别单元格里的 ~$#&^ 标记,动态填充数据生成新 Excel。
~dsName.colName → 多行展开(一行数据生成一行输出)
$dsName.colName → 单行取值(取第一条数据)
&userName → 系统变量
^anything → 隐藏行(注释用)
这套语法设计师 2012 年就用了,解决了"每个报表都要写 Java 代码"的问题。
3. 32 个前端 UI 组件
从 TextBox、ComboBox 到 MetaGrid、MetaTree,一共 32 个 Dojo 组件。组件本身不值钱(Element Plus 里全有),值钱的是绑定协议和字典集成。
怎么提取?
不修改原文
这是最重要的原则。ea-component 在 VedioCall 里已经稳定运行了几年,修改原文等于在不稳定的基础上搭建新系统。万一改坏了,影响的是生产系统。
做法:复制。把 ea-core、ea-spring-boot-starter、ea-adapter-browise 三份代码复制到新项目的 browise-metadata 模块中,合并成一个模块。
原文留在 D:workea-component,作为只读参考。
保持包名不变
复制代码时,包名全部保留 com.browise.ea.core.*。不做"重构式迁移"——改包名除了让 diff 难做,没有任何好处。
砍掉过时的依赖
VedioCall 的报表引擎依赖了 jxl(JExcelAPI),这个库只支持 .xls 格式,2009 年就停止维护了。
提取时做了一次升级:jxl → Apache POI 5.2.5。好处:
- 支持 .xlsx
- POI 还在活跃维护
- 5.2.5 是 Java 8 兼容的最新版本
重写而非迁移的模块
前端 32 个组件和核心数据层(RowSet、绑定、字典)没有从 Dojo 原文迁移——它们是全新编写的。
为什么?Dojo 的 JavaScript 和 Vue 3 的 TypeScript 差异太大,逐行迁移不如重新实现。但设计不变——保留了绑定协议、脏标记、三缓冲的概念,只是换了一套实现语言。
额外新写的部分
前端核心层(7 个 TypeScript 文件)
-
useRowSet.ts:Row 类 + RowSet(脏标记版本在浏览器端跑) -
useCenter.ts:Store 管理器,对应 Dojo 的 DataCenter -
useBinding.ts:provide/inject 绑定协议 -
useDict.ts:字典中心 -
httpClient.ts:axios 封装
通用工具(4 个 Java 文件)
-
Result.java:统一 API 响应 -
BrowiseException.java:异常封装 -
StringUtil.java:字符串工具 -
DesensitizeUtil.java:数据脱敏
Demo(含报表接口)
一个 Spring Boot 启动类 + 一个 ReportController,验证后端可以跑起来。
最终架构
browise/
├── browise-common # 通用工具(4 Java 文件)
├── browise-metadata # 元数据 SQL 引擎(32 Java 文件,从 ea-component 复制)
├── browise-report # 报表引擎(7 Java 文件,参照 FileUtil.java 重写)
├── browise-demo # 演示应用(含报表接口)
├── browise-vue # 前端(约 50 个源文件)
├── browise-crypto # 骨架
├── browise-data # 骨架
├── browise-dict # 骨架
├── browise-workflow # 骨架
├── browise-formbuilder # 骨架
├── browise-notify # 骨架
├── browise-spring-boot-starter # 骨架
提取的:ea-component(32 Java 文件)→ browise-metadata
参照重写的:FileUtil.print + ToPDF → browise-report
全新编写的:前端全部 + browise-common + browise-demo
骨架待做的:crypto / data / dict / workflow / formbuilder / notify / starter
一点经验
从遗留项目提取平台,比从零造轮子更难。难在两点:
第一,要分得清"核心资产"和"历史债务"。
不是所有在生产系统里跑的代码都值得提取。<table> 布局写的 JSP 页面不值钱,但 binding 协议值钱。日志输出的工具类不值钱,但 SQL 引擎值钱。
第二,要有克制力。
提取时总想顺便重构、顺便升级、顺便改包名。克制住。先保证提取出来的东西能编译、能运行。改进是提取之后的事。
第三篇文章聊:32 个 Vue 组件的设计取舍——为什么不用 adapter 层、为什么 options 通过字典中心、为什么提供 23 种字段类型。