当前位置: 首页 > news >正文

当所有低代码都在卷画布时,我们押注了源代码本身


当所有低代码都在卷画布时,我们押注了源代码本身

钉钉宜搭、腾讯微搭、简道云、JeecgBoot……

过去两年,国内每一家低代码厂商的发布会,PPT 几乎是同一张:一个浏览器画布、一个 AI 副驾驶、一句"业务人员也能搭"

只有 Erupt 在做一件反方向的事——

一行 @Erupt 注解,一个 DataProxy<T> 扩展点,一组 Handler 接口。

没有画布。

没有"AI 生成代码"。

注解,就是 UI Schema 本身。

这一期,把我们为什么没去做拖拽画布的工程理由讲透。


01|国内"低代码"三个字底下,藏着三种完全不同的东西

先做一个不太友好的拆解。

市面上喊自己"低代码"的产品,可以分成三派——

第一派:画布即应用

代表:钉钉宜搭、腾讯微搭、简道云、明道云。

特点:浏览器里画一个表单,发布就能用。配置存在 SaaS 内部数据库里,导出仅作为备份。

适合:业务部门、运营、轻 IT。

第二派:画布生成代码

代表:JeecgBoot、JNPF。

特点:在线设计器画好表单,导出一份 Java + Vue 代码给你拿回去改。

适合:想快速跑通 PoC 的 Java 小团队。

第三派:代码即配置

代表:Erupt

特点:没有画布,没有"生成",注解就是配置

适合:有工程团队、领域模型稳定、合规审计是硬约束的项目。


02|画布派最大的隐藏成本,不是"会用",而是"长大之后"

听起来很反直觉,但仔细想想——

画布派的产品前两个月真的爽:业务自己拖几下,admin 后台就跑起来了。

可是当系统活到第二年,下面这些问题会一起冒出来:

  • 业务逻辑稍微复杂一点,画布属性面板里写的那段 JS 就开始"看不懂、不敢删、不能测"。
  • 想 code review?只能截图对比。
  • 想跨环境部署?只能"导出应用包"。
  • 想跑单测?没有这个概念。
  • 想接外部 HTTP / 消息队列 / Redis?要么去找平台扩展,要么不行。

第二派"画布生成代码"听起来折中,但它有一个致命的双向同步问题——

一旦你回到 IDE 改了 service 层,画布就不再可信。下次想用画布再加个字段,要么承担合并冲突,要么放弃画布。

最后大家都在做同一件事:用画布生成完之后,永远不再回画布

那它和"脚手架"的区别,到底在哪里?


03|Erupt 的反向押注:领域模型 + 注解 = UI

直接看代码——

@Erupt(name = "客户",power = @Power(importable = true, export = true)
)
@Table(name = "t_customer")
@Entity
public class Customer extends BaseModel {@EruptField(views = @View(title = "客户名"),edit  = @Edit(title = "客户名", notNull = true, search = @Search))private String name;@EruptField(views = @View(title = "等级"),edit  = @Edit(title = "等级",type  = EditType.CHOICE,choiceType = @ChoiceType(vl = {@VL(value = "A", label = "A 类"),@VL(value = "B", label = "B 类")})))private String level;
}

3 个注解 + 2 个字段,Erupt 自动给你生成——

✅ 列表页(搜索框、Excel 导入导出、按等级过滤)

✅ 新建 / 编辑表单(必填校验、下拉选项)

✅ 权限 / 菜单 / API endpoint

✅ 前端表格行为(排序、列宽、操作列)

为什么这么短的注解能撑起整个 UI?

打开 erupt-core/proxy/AnnotationProxyPool.java 你会看到:Erupt 启动时把 @Erupt@EruptField@View@Edit 这些注解通过 AnnotationProxy<T,R> 序列化成 JSON,前端 Angular 拿到 JSON 就动态渲染界面。

也就是说——

注解不是装饰品,注解就是 UI Schema 的物化形态。

只不过这份 schema 写在源码里、被 IDE 自动补全、被 Git 版本管理。


04|业务逻辑写在哪?写在 Spring Bean 里

画布派被问到的第一个问题永远是:

那如果业务逻辑很复杂怎么办?

宜搭、微搭的答案是"事件 + JS 片段"——你在画布属性面板里写 function onSubmit(formData) { ... }没有 IDE、没有 Spring 容器、没有事务

JeecgBoot 的答案是"回 IDE 改 service"——然后画布就废了

Erupt 的答案在 erupt-annotation 里有一个接口:

public interface DataProxy<MODEL> extends MetaProxy<MODEL> {default void validate(MODEL model) throws EruptException {}default void beforeAdd(MODEL model) {}default void afterAdd(MODEL model) {}default void beforeUpdate(MODEL model) {}default void afterUpdate(MODEL model) {}default void beforeDelete(MODEL model) {}default void afterDelete(MODEL model) {}// ...
}

任意实现这个接口的 Spring Bean,被 @Erupt(dataProxy = ...) 引用之后,就在 admin 的增删改查生命周期里跑。

它是普通的 @Service,所以——

🔸 能 @Autowired 任何东西

🔸 能打 @Transactional@PreAuthorize

🔸 能调 JPA、Redis、MQ、HTTP

🔸 能 code review、写单测、IDE 重构

@Service
public class CustomerProxy implements DataProxy<Customer> {@Resource private CustomerService service;@Resource private AuditLogger auditLogger;@Override@Transactionalpublic void beforeAdd(Customer model) {service.assertNameUnique(model.getName());model.setOwnerId(MetaContext.getUser().getId());}@Overridepublic void afterUpdate(Customer model) {auditLogger.log("customer.update", model.getId());}
}

和画布派"在属性面板里写 JS"的本质区别是——

这段代码,跟你 service 层共享同一个事务管理器、同一个安全上下文、同一份单元测试。


05|所有"动态行为",都收敛到 Java 接口

画布派第二个常吹的点是"无代码动态行为"——

某个下拉框的选项动态拉取、某行只对管理员可见、某个按钮触发自定义流程……

画布派的方案是"事件配置面板 + 自创 DSL"。

Erupt 的方案是 Handler 接口

想做的事 在注解里写 实现这个接口
数据过滤(行级权限) @Filter(conditionHandler=…) FilterHandler
自定义操作按钮 @RowOperation(operationHandler=…) OperationHandler
动态权限控制 @Erupt(powerHandler=…) PowerHandler
下拉选项动态拉取 @ChoiceType(fetchHandler=…) ChoiceFetchHandler
输入框自动补全 @InputType(autoCompleteHandler=…) AutoCompleteHandler

源码位置:erupt-annotation/src/main/java/xyz/erupt/annotation/fun/

举个最常见的——只让用户看到自己创建的订单:

@Service
public class MyOrderFilter implements FilterHandler {@Overridepublic String filter(String condition, String[] params) {Long uid = MetaContext.getUser().getId();return "ownerId = " + uid;}
}@Erupt(name = "订单",filter = @Filter(conditionHandler = MyOrderFilter.class)
)
@Entity
public class Order extends BaseModel { /* ... */ }

注意这里的设计选择——

Handler 不是字符串表达式,不是平台 DSL,是一个真的 Java 接口。

这意味着——

✅ 能 @Autowired 注入 RoleServiceTenantContext

✅ 能写单元测试

✅ 能 IDE 跳转、追引用、重构

✅ 复杂逻辑(多租户、季度切片、A/B 实验)就是普通 Java,不需要学任何"低代码 DSL"

我们的赌注是——

宁可让你写 6 行 Java,也不要让你学一套只能用一次的 DSL。


06|跟国内主流低代码到底怎么比?

放一张干货对比,截图收藏用——

真理来源

宜搭:SaaS 画布的内部 DB

JeecgBoot:一次性生成的 .java / .vue

Erupt:Git 里的 .java 源文件

加一个字段

宜搭:进画布配 → 同步表结构

JeecgBoot:改实体 + 改 Vue + 改 mapper

Erupt:@EruptField 加一行

Diff / Review

宜搭:截图对比

JeecgBoot:git diff(但 diff 的是自动生成的代码)

Erupt:git diff,且只 diff 注解

业务逻辑写在哪

宜搭:表单后端事件 + JS 片段

JeecgBoot:改 service / controller

Erupt:Spring Bean + DataProxy<T>

跨环境部署

宜搭:应用包导入导出

JeecgBoot:jar + 同步 SQL

Erupt:mvn package 一个 jar


我们不是在说画布派一定错——

对没有工程团队的业务部门来说,"在浏览器里搭出一个查库 App"就是真实生产力。

JeecgBoot 这类生成派也有它的位置——

只要你只关心"快速跑起来",且永远不会回到画布,它是合理的脚手架。

但当系统已经长大、领域模型稳定、合规和审计是硬约束时——

画布即应用会撞上「逻辑表达力上限」。

画布生成代码会撞上「双向同步漂移」。

这两个问题在第一性原理上都不可解——因为它们都在尝试"既要画布的轻,又要代码的强"。

Erupt 的反向押注是:

承认代码本身就是低代码的下限。
注解已经是配置面,再压缩就不诚实了。

剩下的事,交给 IDE、Git、Spring——这套已经被验证了 20 年的工具链。


07|5 分钟跑通:从空项目到 admin 页面

如果你看完想立刻动手,下面这条路径已经踩平了——

Step 1:建一个空 Spring Boot 工程,引入 erupt-jpa 依赖

Step 2:在 application.yml 配数据库

Step 3:写第一个带 @Erupt 的实体

Step 4:启动,访问 /,默认账号 erupt / erupt

整个过程不超过 5 分钟。

跑通之后,把本文 §04(DataProxy)和 §05(Handler)翻回来对照——

加业务逻辑写 DataProxy<T>

加动态过滤写 FilterHandler

加自定义按钮写 OperationHandler

每一步都是写 Java,每一步都被 IDE、被 Git、被 CI 接管,没有任何一步回到画布。


写在最后

低代码的尽头,可能不是 AI 自动拖拽。

而是——

让代码本身,成为最小的配置面。

如果你认同这条路,欢迎做三件事——

GitHub 给 Erupt 点个 Star:github.com/erupts/erupt

📌 关注公众号:每周三一篇深度技术文

💬 加入 Erupt 用户群:后台回复"加群"

本文由mdnice多平台发布

http://www.gsyq.cn/news/1382223.html

相关文章:

  • 如何快速掌握JavaScript异步编程:Async-JavaScript-Cheatsheet项目完全解析
  • nnAudio部署指南:跨平台兼容性与生产环境最佳实践
  • 如何用WaveTools实现《鸣潮》性能优化:从卡顿到流畅的完整解决方案
  • RookieAI_yolov8:基于YOLOv8的智能目标检测与交互系统技术解析
  • 基于树莓派与433MHz射频模块的无线智能家居系统DIY指南
  • 大湾区民营建筑企业排名/排行榜 - 奔跑123
  • 如何选择深圳环保板材全屋定制?2024年决策维度与趋势解析 - 产品测评官
  • 5分钟解决Umi-OCR启动崩溃:OCR引擎插件缺失的终极修复指南
  • 小程序真机抓包实战:HTTPS解密与微信开发者工具联动
  • 如何用eSpeak NG实现127种语言的免费文本转语音?终极指南
  • 粤港澳大湾区实力民营建企排行/排行榜 - 奔跑123
  • 不想直接用 hccl?第一次了解 hcomm 能做什么
  • 第一次做 PD 分离推理?先了解 hixl 能做什么
  • B站CC字幕下载神器:三步搞定视频字幕,离线学习超简单!
  • 这个Skill太香了!Karpathy说的AI写代码的毛病,直接治好
  • FreeJ2ME:现代设备上重温经典J2ME游戏的终极指南
  • eSpeak NG共振峰合成引擎架构解析与多语言TTS集成实战
  • 揭秘Midjourney V6霓虹渲染底层逻辑:为何--stylize 1000反而毁掉光晕?RGB偏移阈值与--sref权重的黄金配比首次公开
  • Android BLE蓝牙开发实战:使用BluetoothKit框架实现高效设备通信
  • 为你的OpenClaw智能体工作流配置Taotoken作为稳定模型供应商
  • 终极指南:如何快速下载网站Git仓库并恢复完整代码
  • 【2026实测】怎么提高论文原创度?盘点8款主流降AI工具,附结构级优化指南
  • Social Likes三大皮肤主题深度对比:如何选择最适合您网站的社交按钮样式
  • 如何用LabelImg2快速完成图像标注:从零开始的完整指南
  • 用PyTorch复现FactorVAE:一个能同时预测收益和风险的量化模型实战教程
  • 2026贵阳高端美容院推荐|皮肤管理避坑指南与官方对接通道 - 精选优质企业推荐官
  • 创业团队如何借助 Taotoken 统一管理多个 AI 项目的 API 成本与用量
  • 微信聊天图片丢了别慌!保姆级教程:找回并解密DAT文件(支持新旧版微信路径)
  • Autodesk Fusion 360在Linux上的技术实现与性能优化深度解析
  • 如何深度定制索尼相机:Sony-PMCA-RE逆向工程工具完整指南