模型驱动开发:动态表单基础
本文是“统一模型驱动开发”的入门篇,最简要地展示了如何以模型驱动的方式,声明式的定义一个动态表单的开发过程。
本文的重点是讲解基本的开发过程,包括:如何定义数据模型,数据服务,前端表单组件,以及如何声明式地讲表单组件与数据模型和服务绑定,实现动态的展现表单结构、交互操作,以及如何进行开发调试。
文本不涉及复杂表单功能的示例,这将在《动态表单进阶》教程中进行讲解。
准备条件
进行开发之前,首先需要创建一个应用项目。
默认有两种应用模板——单模块项目、多模块项目两种模板,采用不同的应用模板创建的应用项目的结构不同,具体请参考:《开发指南 > 应用配置 > 应用项目结构》 。
本示例中,选择采用“简单应用模板(simple-gapp-template)”,创建一个单模块的 GAPP 应用项目,具体参考《开发指南 > 应用开发 > 创建应用项目》 。
定义数据模型
默认情况下,应用模板在创建项目时提供了一个数据模型的示例 my.galaxy.demos.sample_001.sample1.web.SampleVO
,位于后端源代码目录(src/main/java
)之下。
说明
在示例中,尽管数据模型的形式上以 Java 类呈现,但是,标注(
Annotation
)的语义具有一般性,这些标注(Annotation
)以及对应的类型系统由 “星河低代码应用开发框架(galaxyframework
)” 专门设计,具有跨语言的通用语义,并不特定于后端或前端的某一种编程语言的类型系统。因此,由于采用了一般性的语义定义,使得数据模型可以保持一致地在前后端共享。
package my.galaxy.demos.sample_001.sample1.web;
import com.linkgie.galaxyframework.metadata.DataEntity;
import com.linkgie.galaxyframework.metadata.DataField;
import com.linkgie.galaxyframework.metadata.DataInterface;
import com.linkgie.galaxyframework.metadata.DataKey;
import com.linkgie.galaxyframework.metadata.DataLabel;
import com.linkgie.galaxyframework.metadata.DataType;
@DataInterface
@DataEntity
public class SampleVO {
@DataKey
@DataField(name = "Id", order = 0, readonly = true)
private String id;
@DataLabel
@DataField(name = "名称", order = 1)
private String name;
@DataField(name = "值", order = 2)
private int value;
@DataType(contentType = "plain;multiline=true")
@DataField(name = "描述", order = 3)
private String description;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
定义数据服务
以 Spring Controller 定义基于 HTTP Restful 接口的数据服务,提供对数据的访问和编辑。
package my.galaxy.demos.sample_001.sample1.web;
import java.util.LinkedHashMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import com.linkgie.galaxyframework.utils.CollectionUtils;
import com.linkgie.galaxyframework.web.HttpDelete;
import com.linkgie.galaxyframework.web.HttpGet;
import com.linkgie.galaxyframework.web.HttpPost;
import com.linkgie.galaxyframework.web.HttpPut;
import com.linkgie.galaxyframework.web.HttpService;
@HttpService
public class SampleController{
private LinkedHashMap<String, SampleVO> sampleVos = new LinkedHashMap<>();
/**
* 初始化示例数据;
*/
public SampleController() {
for (int i = 0; i < 4; i++) {
SampleVO sampleVO = new SampleVO();
sampleVO.setId("X-" + i);
sampleVO.setName("数据-" + i);
sampleVO.setValue(10 + i);
sampleVos.put(sampleVO.getId(), sampleVO);
}
}
@HttpGet("/sample1/list")
public SampleVO[] getList() {
return CollectionUtils.toArray(this.sampleVos.values(), SampleVO.class);
}
@HttpPost("/sample1/data")
public void create(@RequestBody SampleVO data1) {
this.sampleVos.putIfAbsent(data1.getId(), data1);
}
@HttpPut("/sample1/data")
public void update(@RequestBody SampleVO data1) {
this.sampleVos.put(data1.getId(), data1);
}
@HttpDelete("/sample1/data/{id}")
public void delete(@PathVariable("id") String id) {
// TODO: 删除;
}
}
创建视图
创建视图的过程就是定义一项功能,并使其可被授权和访问的过程,包含 3 个步骤:
创建视图
创建一个视图组件,用于实现一项功能的人机交互界面。
注册菜单权限
注册一项菜单,菜单项与功能的视图组件绑定,赋予功能一个权限码,使一项功能可在权限体系中被授权。
授权菜单权限
将一项菜单权限授予给特定的主体(机构、成员、用户),使菜单关联的功能变得可访问。根据授权方式的不同,一个功能可以被定义成不同的访问范围:完全公开访问、特定角色可访问、特定机构可访问、特定用户/账号可访问等。
关于创建视图的更详细教程,请参考《创建新功能:视图与菜单》
创建视图组件
“视图组件” 定义了前端页面最主要的功能区域,与一项特定的功能菜单关联。在默认布局下,当菜单被点击时,关联的视图组件被激活,并显示在“视图”区域。
在 web/src/views
目录下创建一个 VUE 组件 simple-form.vue
,将组件文件的内容编辑如下:
在编译加载之后,该视图组件会被自动注册,并赋予路由路径为 simple-form.view
。
<template>
<x-view title="基本表单">
<h1><x-icon icon="bs-svg-brightness-high" width="1.5rem" height="1.5rem" /> 演示基本表单 </h1>
</x-view>
</template>
<!-- 脚本 -->
<script>
export default {
// 组件属性
props: {
// ...
},
// 状态数据
data() {
return {
//...
};
},
// 注入属性
// inject: [],
// 计算属性
computed: {},
// 方法
methods: {},
};
</script>
<!-- 样式 -->
<style scoped></style>
目录下的每一个
.vue
文件都视为一个视图组件,组件会自动注册为路由组件,并赋予一个由文件名称命名的路由路径,例如:视图组件views/test.vue
的路由路径是/test.view
;
注册菜单权限
在“应用功能清单” @profiles/application.profile
中增加一项菜单项 simple-form
,便能将视图组件的路由路径与菜单绑定,完成了将视图组件挂载到页面。
{
"applicationId": "sample-001",
"applicationName": "示例001-快速开发表单-1",
// ...
"features": {
"menus": [
//...
// 新增的菜单项
{
key: "simple-form",
name: "基本表单",
icon: "bs-svg-house-door",
href: "simple-form.view",
}
],
}
}
授权菜单权限
一项“菜单”需要经过显式地授权给具体的机构成员之后,才能被访问。
本示例通过配置文件授权给机构 testcom
的成员 member1
,在 @conf/organization.conf
加入以下配置:
#######################################
# 授权配置;
#######################################
# ...
# 是否允许通过配置文件进行直接授权;默认为 false ;
galaxyplatform.security.authorization.configurable=true
# ...
# 授权给机构 testcom 的成员 member1 ;
galaxyplatform.security.authorization.orgs.testcom.members.member1.authorities=FEATURE://APPLICATION/MENU/SIMPLE-FORM
注
菜单的“权限代码”是根据菜单项的 key 和菜单项所处的 profile 文件决定的,格式为:'FEATURE://' + profile文件的Key + Menu树中菜单项的Key路径。
例如,
simple-form
菜单项是在application.profile
中的MENU
一节声明的,位于菜单树的根,对应的授权码为FEATURE://APPLICATION/MENU/SIMPLE-FORM
。
定义表单
在星河低代码中,开发一个表单不需要编写复杂的 HTML、JS、CSS ,只需要使用最简单的 HTML 标签,采用声明式的标签组件与数据模型与服务进行绑定。
定义表单组件
在前端视图中,引入 动态数据表单组件(x-dataform
) ,采用声明式语义,将数据模型的声明信息绑定到 动态数据表单组件(x-dataform
) 的属性。
<template>
<x-view title="基本表单">
<!-- ... -->
<!-- x-dataform 数据表单组件:提供数据表单形式的交互,通过绑定一个数据源便可以动态地生成表单样式 -->
<x-dataform
title="样例数据"
writeonly
data-interface="my.galaxy.demos.sample_001.sample1.web.SampleVO"
>
</x-dataform>
</x-view>
</template>
定义数据源组件
数据源组件 x-datasource
提供了与 HTTP 服务绑定的功能,可声明式地定义如何从 HTTP 服务中加载数据,以及如何响应绑定的 UI 组件的交互操作。
<template>
<x-view title="基本表单">
<!-- ... -->
<!-- x-datasource 数据源组件:定义数据的类型和来源,并提供数据集合的状态管理 -->
<x-datasource
name="ds-sample-data"
model="my.galaxy.demos.sample_001.sample1.web.SampleVO"
default-current-row-index="0"
>
<!-- x-http-binding 数据绑定组件:用于将数据源的操作与某个 HTTP 接口绑定,如查询、插入、更新等。按照 Cont -->
<x-http-binding name="query" service="sample-controller" method="GET" path="/sample1/list"></x-http-binding>
<x-http-binding name="update" service="sample-controller" method="PUT" path="/sample1/data" refresh></x-http-binding>
</x-datasource>
</x-view>
</template>
绑定表单与数据源
将表单组件的 data-binding
属性设置为数据源组件的名称 (name
属性),便实现了表单与数据源的绑定:
- 表单根据数据源的数据模型自动呈现字段;
- 表单从数据源加载数据,并在触发新增、保存等操作时,调用数据源组件的对应 HTTP-Binding 方法。
<template>
<x-view title="基本表单">
<!-- ... -->
<!-- x-dataform 数据表单组件:提供数据表单形式的交互,通过绑定一个数据源便可以动态地生成表单样式 -->
<x-dataform
data-binding="ds-sample-data"
>
</x-dataform>
</x-view>
</template>
表单视图完整代码
<template>
<x-view title="基本表单">
<h1><x-icon icon="bs-svg-brightness-high" width="1.5rem" height="1.5rem" /> 演示基本表单 </h1>
<x-divider></x-divider>
<!-- x-dataform 数据表单组件:提供数据表单形式的交互,通过绑定一个数据源便可以动态地生成表单样式 -->
<x-dataform
title="样例数据"
writeonly
data-interface="my.galaxy.demos.sample_001.sample1.web.SampleVO"
data-binding="ds-sample-data"
>
</x-dataform>
<!-- x-datasource 数据源组件:定义数据的类型和来源,并提供数据集合的状态管理 -->
<x-datasource
name="ds-sample-data"
model="my.galaxy.demos.sample_001.sample1.web.SampleVO"
default-current-row-index="0"
>
<!-- x-http-binding 数据绑定组件:用于将数据源的操作与某个 HTTP 接口绑定,如查询、插入、更新等。按照 Cont -->
<x-http-binding name="query" service="sample-controller" method="GET" path="/sample1/list"></x-http-binding>
<x-http-binding name="update" service="sample-controller" method="PUT" path="/sample1/data" refresh></x-http-binding>
</x-datasource>
</x-view>
</template>
更多的前端组件,请参考 星河低代码前端开发框架 FlexUE
调试运行
启动后端服务,运行前端调试,访问 http://localhost:5173/
,填写或刷新表单数据,验证表单和数据服务的交互操作。
关于启动调试运行的详细教程,请参考《创建新功能:视图与菜单#调试运行》
视频教程
<待上传>