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

低代码表单引擎刷新机制

一、背景

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

具体业务场景参考如下:

分数子表:

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

  • 单元测试分数:例如 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的全民数智化解决方案,包括连接器工厂、业务编排、数据集成等核心能力,带动全员进行数字化创新。

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

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

相关文章:

  • Redis 存在线程安全问题吗?为什么?
  • 排查JVM的一些命令
  • langchain系列 - FewShotPromptTemplate 少量示例
  • Linux 和 Windows 区别
  • C++的封装(十五):第四种访问控制
  • STL 在线转 3MF,开启 3D 模型转换新体验
  • krpano学习笔记,端口修改,krpano二次开发文档,krpano三维div信息展示,krpano热点显示文字
  • Java 中的方法参数传递与值传递
  • 面试题之介绍下call,apply,bind相同点和不同点
  • linux 搭建nfs服务(共享文件夹)
  • 探索HarmonyOS的UI开发新境界:从基础到进阶的深度解析
  • leetcode刷题第十三天——二叉树Ⅲ
  • arm环境下,wpa_supplicant交叉编译+wifi sta连接详解
  • LeetCode-524. 通过删除字母匹配到字典里最长单词
  • 科普:“docker”与“docker compose”
  • go语言 创建kratos框架工程
  • zookeeper Watcher
  • UEFI Spec 学习笔记---9 - Protocols — EFI Loaded Image
  • 【Ubuntu】GPU显存被占用,但显示没有使用GPU的进程
  • 虚拟机和主机可互相复制粘贴
  • wordpress 问答 主题 knowhow/seozhun
  • html网页标题代码怎么写/su搜索引擎优化
  • 免费看今天开始做女神的网站/国际新闻界官网
  • 网站设计风格确认书/网络营销的整体概念
  • 企业网络广告推广方案/seod的中文意思
  • 网站建设赛车/百度推广官网登录