从遗留项目提取低代码平台

AI1天前发布 beixibaobao
3 0 0

从遗留项目提取低代码平台:browise 的诞生

文章目录

  • 从遗留项目提取低代码平台:browise 的诞生
    • 引子
    • 提取什么?
      • 1. 元数据驱动 SQL 引擎(ea-component)
      • 2. 报表模板引擎(FileUtil.print)
      • 3. 32 个前端 UI 组件
    • 怎么提取?
      • 不修改原文
      • 保持包名不变
      • 砍掉过时的依赖
      • 重写而非迁移的模块
    • 额外新写的部分
      • 前端核心层(7 个 TypeScript 文件)
      • 通用工具(4 个 Java 文件)
      • Demo(含报表接口)
    • 最终架构
    • 一点经验

引子

我手上有两个项目:

  1. VedioCall:2004 年起的政务框架,一路从 Struts 1 演进到 Spring Boot
  2. 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 种字段类型。

© 版权声明

相关文章