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

低代码表单引擎刷新机制

一、背景

在低代码产品的研发过程中,表单引擎扮演着至关重要的角色。它涉及前后端的数据解析和触发刷新能力,以满足用户在选择单选框等操作时带出其他数据计算的需求。然而,这些计算往往无法通过前端简单计算得出,需要后端执行脚本或数据库查询来实现。因此,设计高效的表单引擎刷新机制显得尤为重要。

具体业务场景参考如下:

分数子表:

学生的成绩页面有多个子表,分别用于填写各项成绩:

  • 单元测试分数:例如 85、90、78。
  • 作业分数:例如 88、92。
  • 期末考试分数:例如 95。

总分和均分:

页面展示该学生的 总分均分,会根据分数子表的变动实时刷新。

逻辑:

  • 当教师在子表中新增或修改一个分数时,系统会触发刷新逻辑。
  • 总分 为所有分数的累加结果。
  • 均分 为所有分数的平均值(保留两位小数)。
  • 系统需要保证前后端通信高效,避免不必要的全量刷新。

二、刷新模式选型

在选择前后端交互模式时,我们考虑了多种常见的刷新机制,并进行了对比分析。

1.定时刷新模式:前端设定一个频率来刷新页面。然而,在低代码表单中,这个频率通常较高,导致服务器资源消耗过大。

2.用户触发模式:在页面中设定一个按钮,让用户通过点击按钮来刷新页面。这种模式对服务端较为友好,因为用户刷新的频率不会非常频繁。但缺点是用户交互和数据响应不够友好。

3.刷新点触发模式:服务端主动解析会触发刷新的点,以及低代码维护者设定的刷新点(触发其他字段刷新机制的字段的信息后续简称刷新点)。当用户每次改动相关的触发点时,前端发起请求获取刷新结果,并解析到页面中。这种模式对用户较为友好,每次刷新的结果都能及时反应到页面中,同时服务端的消耗也较为可控。

在我们的常见场景中,刷新的及时性和交互友好度更为重要,最后选择了刷新点触发模式作为我们的刷新机制。

服务器资源消耗

刷新及时性

用户交互友好度

定时刷新模式

用户触发刷新模式

刷新点触发模式

三、解析刷新点算法

在确定了交互选型之后,服务端需要根据交互逻辑来逐步实现功能点。首先,服务端需要解析所有会触发刷新逻辑的字段。我们采用的方案是,通过解析DSL(领域特定语言)中所有引用了当前字段的其他字段,并写入当前字段的标识来实现。例如,如果A字段的可见条件是B字段为1时,我们会给B字段加上刷新A字段的标识。当前端解析到B字段需要刷新其他字段时,会将B字段作为刷新点发送请求到后端刷新当前页面。

四、服务端刷新点算法

为了高效处理刷新请求,服务端提供了批量处理刷新点的接口。算法采用递归遍历刷新点,并写入刷新点的图结构来实现刷新点的计算以及回归。递归采用广度优先的逻辑,以更加贴近用户的交互顺序逻辑。每计算完刷新点的结果,系统会解析结果,并将结果也解析成新的解析点进入图结构中,后继续进行广度优先的遍历。同时,系统对无效或者重复解析的数据进行剪枝,以提高计算的有效性。

五、伪代码

import java.util.*;

public class FieldRefreshLogic {

    // 解析字段依赖关系
    public static Map<String, List<String>> parseDependencies(List<Field> fields) {
        Map<String, List<String>> dependencyMap = new HashMap<>();
        for (Field field : fields) {
            for (String referencedField : field.getConditions()) {
                dependencyMap
                    .computeIfAbsent(referencedField, k -> new ArrayList<>())
                    .add(field.getName());
            }
        }
        return dependencyMap;
    }

    // 标记刷新逻辑
    public static Map<String, List<String>> markRefreshFields(Map<String, List<String>> dependencyMap) {
        Map<String, List<String>> refreshMap = new HashMap<>();
        for (Map.Entry<String, List<String>> entry : dependencyMap.entrySet()) {
            refreshMap.put(entry.getKey(), entry.getValue());
        }
        return refreshMap;
    }

    // 服务端处理刷新请求
    public static Map<String, Object> handleRefreshRequest(
            Map<String, List<String>> refreshMap, String changedField) {
        if (refreshMap.containsKey(changedField)) {
            List<String> fieldsToRefresh = refreshMap.get(changedField);
            // 重新计算字段值(这里需要补充具体的计算逻辑)
            return recalculateFields(fieldsToRefresh);
        }
        return Collections.emptyMap();
    }

    // 模拟字段重新计算逻辑
    public static Map<String, Object> recalculateFields(List<String> fieldsToRefresh) {
        Map<String, Object> refreshedData = new HashMap<>();
        for (String field : fieldsToRefresh) {
            // 示例:设置新的值(实际逻辑根据需求实现)
            refreshedData.put(field, "newValue");
        }
        return refreshedData;
    }

    // 前端触发刷新逻辑
    public static void frontendOnFieldChange(String changedField) {
        // 模拟发送请求到后端
        Map<String, Object> response = handleRefreshRequest(refreshMap, changedField);
        if (!response.isEmpty()) {
            // 更新前端页面
            updateUI(response);
        }
    }

    // 模拟更新前端 UI
    public static void updateUI(Map<String, Object> data) {
        data.forEach((key, value) -> System.out.println("Field: " + key + ", New Value: " + value));
    }

    // 示例字段类
    static class Field {
        private String name;
        private List<String> conditions;

        public Field(String name, List<String> conditions) {
            this.name = name;
            this.conditions = conditions;
        }

        public String getName() {
            return name;
        }

        public List<String> getConditions() {
            return conditions;
        }
    }

    // 主程序
    public static void main(String[] args) {
        // 模拟 DSL 字段
        List<Field> fields = Arrays.asList(
                new Field("A", Arrays.asList("B")),
                new Field("C", Arrays.asList("B"))
        );

        // 服务端初始化
        Map<String, List<String>> dependencyMap = parseDependencies(fields);
        Map<String, List<String>> refreshMap = markRefreshFields(dependencyMap);

        // 模拟前端触发字段变化
        String changedField = "B";
        frontendOnFieldChange(changedField);
    }
}

算法思路

广度优先递归

五、总结

本文全面介绍了低代码表单引擎的刷新机制设计思路,从背景介绍到刷新模式选型、解析刷新点以及服务端刷新点算法等方面进行了详细阐述。通过对比分析不同刷新模式的优缺点,我们最终选择了刷新点触发模式,并给出了具体的实现步骤和算法逻辑。这一设计思路不仅提高了用户交互的友好性,还确保了服务端资源的合理利用。


作者介绍:七巧低代码是以业务应用搭建为核心的aPaaS低代码应用平台,为客户提供aPaaS+iPaaS的全民数智化解决方案,包括连接器工厂、业务编排、数据集成等核心能力,带动全员进行数字化创新。

官网:道一云七巧 - 高效的低代码开发平台 | 快速搭建个性化应用

获取更多技术资料:点击这里


http://www.kler.cn/a/555566.html

相关文章:

  • JWT认证机制
  • 音视频入门基础:RTP专题(9)——FFmpeg接收RTP流的原理和内部实现
  • Python 高级特性-迭代
  • 【VUE3】Vue 3 中列表排序:单字段与多字段排序实现方案
  • C#基础:使用Linq进行简单去重处理(DinstinctBy/反射)
  • Vue实战【后端返回ArrayBuffer时,前端如何处理并成功下载ArrayBuffer文件】
  • 服务器mysql安装-docker容器化(保姆级教学)
  • 全单模矩阵及其在分支定价算法中的应用
  • 【C++第二十章】红黑树
  • Unity 聊天气泡根据文本内容适配
  • 深度学习-2.机械学习基础
  • 影刀RPA中级证书-Excel进阶-开票清单
  • 2025最新智能优化算法:鲸鱼迁徙算法(Whale Migration Algorithm,WMA)求解23个经典函数测试集,MATLAB
  • 访问者模式 Visitor Pattern
  • Elasticsearch 数据建模:从原理到实战的降维打击指南
  • MySQL Binlog 监听:Canal + Spring Boot 实战指南
  • 【分布式理论14】分布式数据库存储:分表分库、主从复制与数据扩容策略
  • 网络协议相关知识有哪些?
  • 一次交换机故障导致的云平台(opensatck+ceph)不可用的记录
  • Compose 定制UI视图