AppBox快速开发框架(开源)开发流程介绍

  目前很多低代码平台都是基于Web用拖拽方式生成界面,确实可以极大的提高开发效率,但也存在一些问题:

  1. 大部分平台灵活性不够,特殊需求需要较大的自定义开发;

  2. 解析json配置的执行效率不是太高;

  3. 大部分平台缺乏后端支持或复杂的业务逻辑支持;

  4. 与后端的数据结构及业务服务不存在强关联,修改后端容易造成前端配置失效;

  5. 大部分平台缺乏移动端及桌面端支持;

  作者通过不断尝试及多年的经验积累创建了AppBox项目,一个快速开发框架,其将应用系统所涉及的数据结构、业务逻辑、用户界面、工作流、报表、权限等抽象为各类型的模型,通过组合模型形成完整的应用系统,也可以在线修改模型以适应业务的需求变更。 由于模型具备规范性和关联性约束,这样可以高效的分析模型间的关系,并减少因修改模型时引入新的缺陷。本文以客户信息管理作为示例简单介绍使用AppBox的开发流程,以便小伙伴们能够快速了解本框架。

一、运行前准备

  • 准备一个空的数据库,目前仅支持PostgreSql;

  • 克隆仓库git clone --recurse-submodules https://github.com/enjoycode/AppBox.git

  • 编译发布WebHost项目;

  • 编译发布BlazorApp项目,并将发布目录内的wwwroot文件夹复制到WebHost的发布目录内;

  • 修改WebHost目录内的appsettings.json文件中的数据库链接;

  • 终端进入WebHost的发布目录,执行dotnet AppBoxWebHost.dll,首次执行会初始化数据库并创建一些内置的模型(如下图所示);

  • 打开浏览器输入开发环境入口 localhost:5000/#/dev ,登录用户名: Admin 密码: 760wb

懒得编译请加作者微信或邮件直接发打包好的(本想用GitHub Release打包,但超过大小限制)

二、创建实体模型

  实体模型用于描述数据结构,可映射存储至指定数据库,也可以不映射至数据库(DTO)。参考下图先选择模型树的Applications->sys->Entities文件夹,然后点击顶部主菜单的New->Entity,在弹出的对话框内输入实体名称"Customer"并选择映射的数据库"Default"。

  在实体设计器的工具条点击"Add"按钮添加实体成员,其中MemberType(成员类型)中的EntityField代表字段,EntityRef代表一对一引用,EntitySet代表一对多引用。

  点击实体设计器工具条点击"Options"按钮切换至选项面板,用于设置实体的主键及索引。

  上述操作完成后,点击主菜单Models->Save保存当前模型,并且点击Models->Publish发布当前实体模型,发布过程中会在数据库创建对应的数据表。

三、创建服务模型

  服务模型以伪代码的形式提供具体的业务逻辑服务,通过主菜单New->Service创建服务模型,并参考下图输入增删改查的方法。同样在操作完成后,点击主菜单Models->Save保存当前模型,并且点击Models->Publish发布当前模型,发布过程中会将伪代码转换为真正的运行时代码并编译为服务插件备用。

四、创建视图模型

  视图模型有两种形式:一种是拖拽方式生成json配置并渲染的界面,适用于快速配置如大屏页面及简单的增删改查页面;另一种是代码的形式描述用户界面,百分百灵活且经过编译后运行性能高。这里只介绍代码形式,通过主菜单New->View新建视图模型,新建对话框的类型选择"Code"方式,参考以下代码分别建立一个表单视图及一个列表视图,并且保存发布。

  • CustomerForm视图

using sys.Entities;

namespace sys.Views;

public sealed class CustomerForm : View
{
    public static Widget Preview() => new CustomerForm(
        new Customer { Code = "", Name = "", Phone = "", Address = "" }
    );

    public CustomerForm(Customer obj)
    {
        Child = new Column
        {
            Spacing = 5,
            Children = 
            {
                new Text("客户信息") { FontSize = 28 },
                new Form
                {
                    LabelWidth = 60,
                    Children =
                    {
                        new ("编号:", new TextInput(obj.Observe(c => c.Code))),
                        new ("名称:", new TextInput(obj.Observe(c => c.Name))),
                        new ("电话:", new TextInput(obj.Observe(c => c.Phone))),
                        new ("地址:", new TextInput(obj.Observe(c => c.Address))),
                    }
                },
                new Container
                {
                    Padding = EdgeInsets.Only(70, 0, 5, 0),
                    Child = new Button("保存", MaterialIcons.Save)
                    {
                        Width = float.MaxValue,
                        OnTap = _ => Save(obj),
                    }
                },
            }
        };
    }
    
    private async void Save(Customer obj)
    {
        try
        {
            await sys.Services.CustomerService.Save(obj);
            obj.AcceptChanges();
            Notification.Success("保存成功!");
        }
        catch (Exception ex)
        {
            Notification.Error($"保存失败: {ex.Message}");
        }
    }
}

  • CustomerList视图

using sys.Entities;

namespace sys.Views;

public sealed class CustomerList : View
{
    public CustomerList()
    {
        Padding = EdgeInsets.All(10);
        Child = new Column
        {
            Spacing = 10,
            Children =
            {
                new Card { Padding = EdgeInsets.All(5), Child = BuildHeader() },
                new Card { Child = BuildBody() }
            }
        };
    }

    private readonly State<string> _searchKey = "";
    private readonly DataGridController<Customer> _dgController = new();

    private Widget BuildHeader() => new Row
    {
        Height = 30,
        Spacing = 10,
        Children =
        {
            new Expanded(),
            new TextInput(_searchKey) { Width = 100, Suffix = new Icon(MaterialIcons.Search) },
            new Button("查询") { OnTap = _ => Fetch() },
            new ButtonGroup
            {
                Children =
                {
                    new Button("新增") { OnTap = _ => OnCreate() },
                    new Button("编辑") { OnTap = _ => OnEdit() },
                    new Button("删除") { OnTap = _  => OnDelete() }
                }
            }
        }
    };

    private Widget BuildBody() => new Expanded(new DataGrid<Customer>(_dgController)
    {
        Columns =
        {
            new DataGridTextColumn<Customer>("编号", t => t.Code) { Width = 60 },
            new DataGridTextColumn<Customer>("名称", t => t.Name),
            new DataGridGroupColumn<Customer>("联系方式")
            {
                Children =
                {
                    new DataGridTextColumn<Customer>("电话", t => t.Phone),
                    new DataGridTextColumn<Customer>("地址", t => t.Address),
                }
            }
         }
    });

    protected override void OnMounted() => Fetch();

    private async void Fetch()
    {
        try
        {
            var list = await sys.Services.CustomerService.Fetch(_searchKey.Value);
            _dgController.DataSource = list;
            _dgController.TrySelectFirstRow();
        }
        catch (Exception ex)
        {
            Notification.Error($"查询客户列表失败: {ex.Message}");
        }
    }

    private void OnCreate() => Dialog.Show("新建客户",
        d => new CustomerForm(new Customer { Code = "", Name = "", Phone = "", Address = "" }
    ));

    private void OnEdit()
    {
        var obj = _dgController.CurrentRow;
        if (obj == null) return;
        Dialog.Show("编辑客户", d => new CustomerForm(obj));
    }

    private async void OnDelete()
    {
        var obj = _dgController.CurrentRow;
        if (obj == null) return;
        try
        {
            await sys.Services.CustomerService.Delete(obj);
            Fetch();
        }
        catch (Exception ex)
        {
            Notification.Error($"删除客户失败: {ex.Message}");
        }
    }
}

Tip1: 可以点击视图模型编辑器上方工具条的"Preview"按钮实时预览效果,也可以点击左侧工具栏的大纲按钮查看预览视图的组件树及其布局,如下图所示:

Tip2: 另外可以在代码编辑器内光标位置右键菜单选择"Goto Definition"跳转至相应的模型定义内,如下动图所示光标定位实体属性然后跳转至实体设计器内:

五、设置路由并生成应用

  以上步骤完成后,我们需要修改HomePage视图注册客户列表视图的路由,先选择HomePage视图,然后主菜单Models->Checkout签出待修改,添加如下图高亮行所示代码,修改HomePage视图后同样需要保存发布,最后需要点击主菜单Apps->BuildApp生成Web应用。

  这样我们就可以在浏览器地址栏直接输入localhost:5000/#/customers访问客户列表视图,如下图所示:

文章转载自:白菜园

原文链接:https://www.cnblogs.com/BaiCai/p/18026244

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/404411.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

统计图雷达图绘制方法

统计图雷达图绘制方法 常用的统计图有条形图、柱形图、折线图、曲线图、饼图、环形图、扇形图。 前几类图比较容易绘制&#xff0c;饼图环形图绘制较难。 还有一种雷达图的绘制也较难&#xff0c;今提供雷达图的绘制方法供参考。 本方法采用C语言的最基本功能&#xff1a; &am…

k8s(2)

目录 一.二进制部署k8s 常见的K8S安装部署方式&#xff1a; k8s部署 二进制与高可用的区别 二.部署k8s 初始化操作&#xff1a; 每台node安装docker&#xff1a; 在 master01 节点上操作; 准备cfssl证书生成工具:&#xff1a; 执行脚本文件&#xff1a; 拉入etcd压缩包…

【目标检测新SOTA!v7 v4作者新作!】YOLO v9 思路复现 + 全流程优化

YOLO v9 思路复现 全流程优化 提出背景&#xff1a;深层网络的 信息丢失、梯度流偏差YOLO v9 设计逻辑可编程梯度信息&#xff08;PGI&#xff09;&#xff1a;使用PGI改善训练过程广义高效层聚合网络&#xff08;GELAN&#xff09;&#xff1a;使用GELAN改进架构 对比其他解法…

Airtest-Selenium实操小课③:下载可爱猫猫图片

1. 前言 那么这周我们看看如何实现使用Airtest-Selenium实现自动搜索下载可爱的猫猫图片吧~ 2. 需求分析和准备 整体的需求大致可以分为以下步骤&#xff1a; 打开chrome浏览器 打开百度网页 搜索“可爱猫猫图片” 定位图片元素 创建存储图片的文件夹 下载可爱猫猫图片…

SpringBoot中Redis缓存的使用

目录 1 前言 2 实现方法 2.1 查询数据时 2.2 修改数据 1 前言 对于一些不常改变&#xff0c;但又经常查询的数据&#xff0c;我们可以使用Redis缓存&#xff0c;来缓解数据库的压力&#xff0c;其中的逻辑如下&#xff1a; 2 实现方法 2.1 查询数据时 一般在控制类查询方…

普中51单片机(DS18B20温度传感器)

DS18B20温度传感器原理 内部结构 64位(激)光刻只读存储器 光刻ROM中的64位序列号是出厂前被光刻好的&#xff0c;它可以看作是该DS18B20的地址序列号。64位光刻ROM的排列是&#xff1a;开始8位&#xff08;28H&#xff09;是产品类型标号&#xff0c;接着的48位是该DS18B20自身…

推荐系统经典模型YouTubeDNN

文章目录 YouTubeDNN概念YouTubeDNN模型架构图YouTubeDNN召回阶段YouTubeDNN层级介绍 YouTubeDNN排序阶段YoutubeDNN模型中的一些Trick负采样问题特征构造上下文选择 总结 YouTubeDNN概念 YouTubeDNN是YouTube用于做视频推荐的落地模型&#xff0c;其大体思路就是召回阶段使用…

Kubernetes 二进制部署 《easzlab / kubeasz项目部署》(一)

Kubernetes 二进制部署 - easzlab / kubeasz项目部署 1. 准备工作1.1 设置防火墙1.2 设置SeLinux1.3 设置时区及时间同步1.4 配置域名解析1.5 确认SSH开启1.6 IP转发1.7 安装docker1.8 关闭swap 2. 服务器规划2.1 基本架构图2.2 官方建议2.3 实践服务器规划 3. 服务器配置3.1 配…

Airtest遇到模拟器无法输入中文的情况该如何处理?

1. 前言 最近有收到同学们的一些提问&#xff0c;使用Airtest的 text 接口&#xff0c;发现在部分模拟器上&#xff0c; text 无法输入中文&#xff0c;不知道该怎么处理。 今天我们就输入这个小问题&#xff0c;来详细聊一下。 2. Airtest的输入法简介 对于Android设备来说…

WebStorm 2023:让您更接近理想的开发环境 mac/win版

JetBrains WebStorm 2023激活版下载是一款强大而智能的Web开发工具&#xff0c;专为提高开发人员的生产力而设计。这款编辑器提供了许多先进的代码编辑功能&#xff0c;以及一系列实用的工具和插件&#xff0c;可帮助您更快地编写、调试和测试代码。 WebStorm 2023软件获取 We…

ESP8266智能家居(1)——开发环境的搭建

1.前期介绍 本次打算使用esp8266的开发板——NodeMCU&#xff0c;进行物联网相关项目的学习。开发环境使用Arduino软件。 NodeMCU实物图为&#xff1a; 开发环境截图为&#xff1a; 2.软件下载 我使用的arduino版本为1.8.5&#xff0c;其安装包如下&#xff1a; 【免费】ar…

五大方法教你如何分分钟构造百万测试数据!

在测试的工作过程中&#xff0c;很多场景是需要构造一些数据在项目里的&#xff0c;方便测试工作的进行&#xff0c;构造的方法有很多&#xff0c;难度和技术深度也不一样。本文提供方法供你选择。 在测试的工作过程中&#xff0c;很多场景是需要构造一些数据在项目里的&#…

Linux理解

VMware安装Linux安装 目录 VMware安装Linux安装 1.1 什么是Linux 1.2 为什么要学Linux 1.3 学完Linux能干什么 2.1 主流操作系统 2.2 Linux系统版本 VMware安装Linux安装 1.1 什么是Linux Linux是一套免费使用和自由传播的操作系统。 1.2 为什么要学Linux 1). 企业用人…

Jenkins 中部署Nodejs插件并使用,并构建前端项目(3)

遇到多个版本nodeJS需要构建的时候 1、第一种就是一个配置安装&#xff0c;然后进行选中配置 2、第二种就是插件&#xff1a;nvm-wrapper&#xff0c;我们还是选用NodeJS插件&#xff1a; &#xff08;1&#xff09;可以加载任意npmrc文件&#xff1b; &#xff08;2&#x…

论文精读--GPT1

把transformer的解码器拿出来&#xff0c;在没有标号的大量文本数据上训练一个语言模型&#xff0c;来获得预训练模型&#xff0c;然后到子任务上微调&#xff0c;得到每个任务所需的分类器 Abstract Natural language understanding comprises a wide range of diverse tasks…

极电电子WMS项目顺利验收,盘古信息助推新能源车企数字化转型

近年来&#xff0c;中国新能源汽车产销持续保持着较高增速&#xff0c;产销总量连续9年位居全球第一。 在产销高涨的背后&#xff0c;新能源汽车行业“内卷”现象也日益加剧&#xff0c;“配置战”、“价格战”等愈发激烈&#xff0c;驱动车企提高自身竞争力&#xff0c;以抢占…

【Ucore 操作系统】2. 批处理系统和特权机制

文章目录 【 0. 引言 】0.1 批处理系统0.2 特权级机制0.3 本章任务 【 1. 特权级机制 】1.1 特权级的软硬件协同设计1.2 RISC-V的特权级架构1.3 异常1.3.1 陷入/trap 类异常1.3.2 Fault 类异常 1.4 RISC-V的特权指令 【 2. 实现应用程序以及user文件夹 】2.1 user文件夹以及测例…

基于springboot+vue的智能物流管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

外贸专线费用解析与选择要点

外贸专线费用解析与选择要点 在进行外贸业务时&#xff0c;一项至关重要的准备工作是申请一条外网专线&#xff0c;以确保企业能够稳定、高效地与国外网络连接&#xff0c;促进业务的正常开展和与国外客户的便捷沟通。然而&#xff0c;对于外贸专线的费用问题&#xff0c;许多初…

【算法与数据结构】127、LeetCode单词接龙

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;示例1为例&#xff0c;hit到达cog的路线不止一条&#xff0c;如何找到最短是关键。广度优先搜索是一圈…