构建低代码平台的技术解析
低代码平台表单引擎与业务事件设计实践
- 低代码平台表单引擎与业务事件设计实践
- 一、什么是低代码?它能做什么?
- 二、请假系统案例介绍
- 2.1 主要功能
- 2.2 业务流程
- 三、表单元数据、实例数据与业务事件联动设计
- 3.1 表单元数据(Meta)如何设计
- 3.2 表单实例数据(Data)如何保存(宽表结构)
- 3.3 业务事件与数据节点的联动
- 四、业务事件与原子策略的实现(详细Java代码)
- 4.1 业务事件类型举例
- 4.2 详细Java实现
- 4.2.1 事件上下文对象
- 4.2.2 原子策略接口
- 4.2.3 具体策略实现
- 4.2.4 策略工厂
- 4.2.5 事件配置对象
- 4.2.6 事件引擎
- 4.2.7 事件驱动示例
- 五、架构设计总结
- 六、常见业务事件场景举例
- 七、数据结构建议(最终版)
- 7.1 表单元数据(MongoDB)
- 7.2 表单实例数据(MySQL,宽表结构)
- 7.3 业务事件(MongoDB)
- 八、结语
低代码平台表单引擎与业务事件设计实践
一、什么是低代码?它能做什么?
低代码(Low-Code)是一种通过可视化拖拽、配置和少量代码开发应用的方式。它极大地降低了开发门槛,让业务人员也能参与到应用搭建中。低代码平台通常具备以下能力:
- 可视化表单设计:通过拖拽组件快速搭建业务表单。
- 流程编排:配置化定义审批流、业务流转。
- 业务规则配置:通过“事件-动作-条件”方式实现复杂业务逻辑。
- 数据集成:对接外部系统、数据库,实现数据互通。
- 快速上线与迭代:大幅缩短开发周期,支持敏捷变更。
低代码平台适用于OA审批、报销、请假、合同、CRM等大量表单驱动的业务场景。
二、请假系统案例介绍
为了更好地理解低代码平台的能力,我们以“请假申请系统”为例,介绍其功能和业务逻辑。
2.1 主要功能
- 员工提交请假申请,填写请假人、请假时间、请假原因等信息。
- 系统自动带出直属领导作为审批人。
- 请假天数超过3天时,自动增加二级、三级审批人。
- 审批人可在系统中审批,审批结果自动流转到下一级。
- 审批通过/拒绝后,自动通知相关人员。
2.2 业务流程
- 员工发起请假申请,填写表单。
- 系统根据申请人自动带出一级审批人。
- 若请假天数>3天,自动增加二级、三级审批人。
- 审批人依次审批,全部通过后流程结束。
- 审批拒绝则流程回退,通知申请人。
三、表单元数据、实例数据与业务事件联动设计
3.1 表单元数据(Meta)如何设计
表单元数据描述了表单的结构、字段、字段属性和字段事件。每个字段可以挂载多个业务事件(如 onChange、onBlur、onSubmit 等),事件与字段通过 eventId 关联。
表单元数据(MongoDB示例):
{"_id": "form_001","appId": "app_001","name": "请假申请表","fields": [{"fieldId": "f1","name": "applicant","type": "input","label": "请假人","required": true,"events": [{"eventId": "event_001"}]},{"fieldId": "f2","name": "manager1","type": "input","label": "第一审批人","required": true},{"fieldId": "f3","name": "manager2","type": "input","label": "第二审批人","required": true},{"fieldId": "f4","name": "manager3","type": "input","label": "第三审批人","required": false},{"fieldId": "f5","name": "reason","type": "textarea","label": "请假原因","required": true},{"fieldId": "f6","name": "startTime","type": "datetime","label": "请假开始时间","required": true},{"fieldId": "f7","name": "endTime","type": "datetime","label": "请假结束时间","required": true},{"fieldId": "f8","name": "result1","type": "select","label": "第一审批结果","required": false},{"fieldId": "f9","name": "result2","type": "select","label": "第二审批结果","required": false},{"fieldId": "f10","name": "result3","type": "select","label": "第三审批结果","required": false}],"formEvents": [{"eventId": "event_002"}],"createdAt": "...","updatedAt": "..."
}
说明:
- 每个字段可配置 events,events 里存 eventId,eventId 指向业务事件配置。
- formEvents 是表单级别的事件(如提交时触发)。
3.2 表单实例数据(Data)如何保存(宽表结构)
表单实例数据采用宽表结构,每个字段单独一列,便于查询和统计。
MySQL表结构(宽表):
CREATE TABLE form_leave (id BIGINT PRIMARY KEY AUTO_INCREMENT,app_id VARCHAR(64),form_id VARCHAR(64),user_id VARCHAR(64),applicant VARCHAR(64),manager1 VARCHAR(64),manager2 VARCHAR(64),manager3 VARCHAR(64),reason VARCHAR(255),start_time DATETIME,end_time DATETIME,result1 VARCHAR(32),result2 VARCHAR(32),result3 VARCHAR(32),status VARCHAR(32),current_node VARCHAR(64),created_at DATETIME,updated_at DATETIME
);
示例数据:
id | app_id | form_id | user_id | applicant | manager1 | manager2 | manager3 | reason | start_time | end_time | result1 | result2 | result3 | status | current_node | created_at | updated_at |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | app_001 | form_001 | u_001 | 张三 | 李四 | 王五 | 赵六 | 家中有事 | 2024-06-01 09:00:00 | 2024-06-03 18:00:00 | 同意 | 同意 | pending | manager1 | 2024-06-10 10:00:00 | 2024-06-10 10:00:00 |
3.3 业务事件与数据节点的联动
业务事件是低代码平台的核心,描述了“何时触发、触发什么、如何处理”。
业务事件配置(MongoDB示例):
{"_id": "event_001","formId": "form_001","trigger": "onChange","sourceField": "applicant","action": "setValue","targetField": "manager1","strategy": "fromEmployeeTable","params": {"sourceField": "applicant","lookupTable": "employee","lookupField": "manager1"}
}
说明:
- trigger:事件触发时机(如 onChange、onSubmit、onApprove 等)
- sourceField:事件源字段
- action:动作类型(如 setValue、validate、block、branch、aggregate 等)
- targetField:目标字段
- strategy:具体的原子策略(如 fromEmployeeTable、calculate、validateRule 等)
- params:策略参数
字段与事件的联动:
- 在表单元数据的字段 events 中,配置 eventId。
- 前端监听字段变化,触发事件,后端根据 eventId 查找事件配置,执行对应策略。
四、业务事件与原子策略的实现(详细Java代码)
4.1 业务事件类型举例
- 字段赋值(setValue):如 applicant 变更时自动填充 manager1/manager2
- 字段校验(validate):如请假天数不能超过 10 天
- 节点新增(addNode):如并签时动态增加审批节点
- 节点聚合(aggregate):如并签节点全部通过后流转
- 流程推进(advance):如审批通过后流转到下一个节点
- 流程阻塞(block):如审批未通过阻塞流程
- 分支判断(branch):如请假天数大于 3 天需三级审批
- 消息通知(notify):如审批人收到待办通知
- 数据计算(calculate):如自动计算请假天数
- 回退(rollback):如审批拒绝回退到上一步
4.2 详细Java实现
4.2.1 事件上下文对象
public class EventContext {private Map<String, Object> fieldValues = new HashMap<>();private Map<String, Object> extra = new HashMap<>();public Object getFieldValue(String fieldName) {return fieldValues.get(fieldName);}public void setFieldValue(String fieldName, Object value) {fieldValues.put(fieldName, value);}public Map<String, Object> getAllFieldValues() {return fieldValues;}public void setExtra(String key, Object value) {extra.put(key, value);}public Object getExtra(String key) {return extra.get(key);}
}
4.2.2 原子策略接口
public interface AtomicStrategy {void execute(EventContext context, Map<String, Object> params);
}
4.2.3 具体策略实现
// 字段赋值策略:根据申请人自动带出直属领导
public class SetValueStrategy implements AtomicStrategy {@Overridepublic void execute(EventContext context, Map<String, Object> params) {String sourceField = (String) params.get("sourceField");String targetField = (String) params.get("targetField");String lookupTable = (String) params.get("lookupTable");String lookupField = (String) params.get("lookupField");String applicant = (String) context.getFieldValue(sourceField);// 假设EmployeeService.getManager(applicant)能查到直属领导String manager = EmployeeService.getManager(applicant);context.setFieldValue(targetField, manager);}
}// 字段校验策略:请假天数不能超过10天
public class ValidateStrategy implements AtomicStrategy {@Overridepublic void execute(EventContext context, Map<String, Object> params) {String startField = (String) params.get("startField");String endField = (String) params.get("endField");int maxDays = (int) params.getOrDefault("maxDays", 10);LocalDateTime start = (LocalDateTime) context.getFieldValue(startField);LocalDateTime end = (LocalDateTime) context.getFieldValue(endField);long days = Duration.between(start, end).toDays();if (days > maxDays) {throw new RuntimeException("请假天数不能超过" + maxDays + "天");}}
}// 分支判断策略:请假天数大于3天需三级审批
public class BranchStrategy implements AtomicStrategy {@Overridepublic void execute(EventContext context, Map<String, Object> params) {String startField = (String) params.get("startField");String endField = (String) params.get("endField");int threshold = (int) params.getOrDefault("threshold", 3);LocalDateTime start = (LocalDateTime) context.getFieldValue(startField);LocalDateTime end = (LocalDateTime) context.getFieldValue(endField);long days = Duration.between(start, end).toDays();if (days > threshold) {context.setFieldValue("needManager3", true);} else {context.setFieldValue("needManager3", false);}}
}// 消息通知策略
public class NotifyStrategy implements AtomicStrategy {@Overridepublic void execute(EventContext context, Map<String, Object> params) {String userField = (String) params.get("userField");String message = (String) params.get("message");String userId = (String) context.getFieldValue(userField);NotificationService.send(userId, message);}
}// 更多策略可按需扩展...
4.2.4 策略工厂
public class StrategyFactory {private static final Map<String, AtomicStrategy> STRATEGY_MAP = new HashMap<>();static {STRATEGY_MAP.put("setValue", new SetValueStrategy());STRATEGY_MAP.put("validate", new ValidateStrategy());STRATEGY_MAP.put("branch", new BranchStrategy());STRATEGY_MAP.put("notify", new NotifyStrategy());// ...注册其他策略}public static AtomicStrategy getStrategy(String strategyName) {return STRATEGY_MAP.get(strategyName);}
}
4.2.5 事件配置对象
public class EventConfig {private String strategy;private Map<String, Object> params;// ...getter/setter
}
4.2.6 事件引擎
public class EventEngine {public void handleEvent(EventConfig eventConfig, EventContext context) {String strategyName = eventConfig.getStrategy();Map<String, Object> params = eventConfig.getParams();AtomicStrategy strategy = StrategyFactory.getStrategy(strategyName);if (strategy != null) {strategy.execute(context, params);} else {throw new RuntimeException("未找到策略: " + strategyName);}}
}
4.2.7 事件驱动示例
// 假设前端触发 applicant 字段 onChange,后端收到事件
EventConfig eventConfig = eventConfigRepository.findById("event_001");
EventContext context = new EventContext();
context.setFieldValue("applicant", "张三");
EventEngine engine = new EventEngine();
engine.handleEvent(eventConfig, context);
// manager1 字段会被自动赋值
五、架构设计总结
- 表单元数据:存储表单结构、字段、字段事件,字段与事件通过 eventId 关联,支持灵活扩展。
- 表单实例数据:采用宽表结构,每个字段单独一列,便于查询和统计。
- 业务事件:存储事件触发条件、动作、目标、策略、参数等,支持灵活配置和复用。
- 原子策略:每个业务事件由一个或多个原子策略组成,策略可扩展、可复用,解耦业务逻辑。
- 事件引擎:根据事件配置,动态组装并执行策略链,实现“配置即逻辑”,大幅提升开发效率。
- 工厂+策略模式:Java 端通过工厂+策略模式实现原子策略的注册与调用,保证系统高扩展性和解耦性。
六、常见业务事件场景举例
- 字段变更自动赋值
- 字段变更自动校验
- 字段变更动态显示/隐藏其他字段
- 审批节点并签/或签
- 审批节点动态新增/聚合
- 审批拒绝回退
- 流程自动推进
- 消息/通知推送
- 数据自动计算
- 数据自动填充(如带出员工信息)
七、数据结构建议(最终版)
7.1 表单元数据(MongoDB)
{"_id": "form_001","appId": "app_001","name": "请假申请表","fields": [{"fieldId": "f1","name": "applicant","type": "input","label": "请假人","required": true,"events": [{"eventId": "event_001"}]},{"fieldId": "f2","name": "manager1","type": "input","label": "第一审批人","required": true},{"fieldId": "f3","name": "manager2","type": "input","label": "第二审批人","required": true},{"fieldId": "f4","name": "manager3","type": "input","label": "第三审批人","required": false},{"fieldId": "f5","name": "reason","type": "textarea","label": "请假原因","required": true},{"fieldId": "f6","name": "startTime","type": "datetime","label": "请假开始时间","required": true},{"fieldId": "f7","name": "endTime","type": "datetime","label": "请假结束时间","required": true},{"fieldId": "f8","name": "result1","type": "select","label": "第一审批结果","required": false},{"fieldId": "f9","name": "result2","type": "select","label": "第二审批结果","required": false},{"fieldId": "f10","name": "result3","type": "select","label": "第三审批结果","required": false}],"formEvents": [{"eventId": "event_002"}],"createdAt": "...","updatedAt": "..."
}
7.2 表单实例数据(MySQL,宽表结构)
CREATE TABLE form_leave (id BIGINT PRIMARY KEY AUTO_INCREMENT,app_id VARCHAR(64),form_id VARCHAR(64),user_id VARCHAR(64),applicant VARCHAR(64),manager1 VARCHAR(64),manager2 VARCHAR(64),manager3 VARCHAR(64),reason VARCHAR(255),start_time DATETIME,end_time DATETIME,result1 VARCHAR(32),result2 VARCHAR(32),result3 VARCHAR(32),status VARCHAR(32),current_node VARCHAR(64),created_at DATETIME,updated_at DATETIME
);
7.3 业务事件(MongoDB)
{"_id": "event_001","formId": "form_001","trigger": "onChange","sourceField": "applicant","action": "setValue","targetField": "manager1","strategy": "fromEmployeeTable","params": {"sourceField": "applicant","lookupTable": "employee","lookupField": "manager1"}
}
八、结语
通过本案例,我们可以看到低代码平台在表单引擎、业务事件、原子策略等方面的强大能力。通过“元数据+事件+策略”驱动的架构,极大提升了业务灵活性和开发效率。未来,低代码平台将成为企业数字化转型的重要基础设施。