构建低代码平台的技术解析

低代码平台表单引擎与业务事件设计实践

一、什么是低代码?它能做什么?

低代码(Low-Code)是一种通过可视化拖拽、配置和少量代码开发应用的方式。它极大地降低了开发门槛,让业务人员也能参与到应用搭建中。低代码平台通常具备以下能力:

  • 可视化表单设计:通过拖拽组件快速搭建业务表单。
  • 流程编排:配置化定义审批流、业务流转。
  • 业务规则配置:通过“事件-动作-条件”方式实现复杂业务逻辑。
  • 数据集成:对接外部系统、数据库,实现数据互通。
  • 快速上线与迭代:大幅缩短开发周期,支持敏捷变更。

低代码平台适用于OA审批、报销、请假、合同、CRM等大量表单驱动的业务场景。


二、请假系统案例介绍

为了更好地理解低代码平台的能力,我们以“请假申请系统”为例,介绍其功能和业务逻辑。

2.1 主要功能

  • 员工提交请假申请,填写请假人、请假时间、请假原因等信息。
  • 系统自动带出直属领导作为审批人。
  • 请假天数超过3天时,自动增加二级、三级审批人。
  • 审批人可在系统中审批,审批结果自动流转到下一级。
  • 审批通过/拒绝后,自动通知相关人员。

2.2 业务流程

  1. 员工发起请假申请,填写表单。
  2. 系统根据申请人自动带出一级审批人。
  3. 若请假天数>3天,自动增加二级、三级审批人。
  4. 审批人依次审批,全部通过后流程结束。
  5. 审批拒绝则流程回退,通知申请人。

三、表单元数据、实例数据与业务事件联动设计

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
);

示例数据:

idapp_idform_iduser_idapplicantmanager1manager2manager3reasonstart_timeend_timeresult1result2result3statuscurrent_nodecreated_atupdated_at
1app_001form_001u_001张三李四王五赵六家中有事2024-06-01 09:00:002024-06-03 18:00:00同意同意pendingmanager12024-06-10 10:00:002024-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 {
    @Override
    public 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 {
    @Override
    public 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 {
    @Override
    public 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 {
    @Override
    public 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 字段会被自动赋值

五、架构设计总结

  1. 表单元数据:存储表单结构、字段、字段事件,字段与事件通过 eventId 关联,支持灵活扩展。
  2. 表单实例数据:采用宽表结构,每个字段单独一列,便于查询和统计。
  3. 业务事件:存储事件触发条件、动作、目标、策略、参数等,支持灵活配置和复用。
  4. 原子策略:每个业务事件由一个或多个原子策略组成,策略可扩展、可复用,解耦业务逻辑。
  5. 事件引擎:根据事件配置,动态组装并执行策略链,实现“配置即逻辑”,大幅提升开发效率。
  6. 工厂+策略模式: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"
  }
}

八、结语

通过本案例,我们可以看到低代码平台在表单引擎、业务事件、原子策略等方面的强大能力。通过“元数据+事件+策略”驱动的架构,极大提升了业务灵活性和开发效率。未来,低代码平台将成为企业数字化转型的重要基础设施。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值