AppBox快速開發框架(開源)開發流程介紹
??目前很多低代碼平臺都是基于Web用拖拽方式生成界面,確實可以極大的提高開發效率,但也存在一些問題:
- 大部分平臺靈活性不夠,特殊需求需要較大的自定義開發;
- 解析json配置的執行效率不是太高;
- 大部分平臺缺乏后端支持或復雜的業務邏輯支持;
- 與后端的數據結構及業務服務不存在強關聯,修改后端容易造成前端配置失效;
- 大部分平臺缺乏移動端及桌面端支持;
??作者通過不斷嘗試及多年的經驗積累創建了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)
.AddTextColumn("編號", t => t.Code, 60)
.AddTextColumn("名稱", t => t.Name)
.AddGroupColumn("聯系方式", out var group)
.AddTextColumnTo(group, "電話", t => t.Phone)
.AddTextColumnTo(group, "地址", 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訪問客戶列表視圖,如下圖所示:

六、小結
??作者個人能力實在有限,目前還有很多Bug待修復,還有工作流引擎及報表引擎待從舊版移植過來,如有問題請郵件聯系或Github Issue,歡迎感興趣的小伙伴們加入共同完善,當然更歡迎贊助項目或給作者介紹工作(目前找工作中)。



浙公網安備 33010602011771號