2.数据源表设计


id
wordId          # 关联到名次表中的wordId,用来做国际化的
requestUrl      # 数据源请求的Url
requestBody     # 请求体
returnType      # 目前仅支持StringList、IntegerList、BooleanList、CombinedList,StringListMap、IntegerListMap、BooleanListMap、CombinedListMap、Custom
describe        # 该字段使用markdown语法,主要是开发人员用于为returnType为Custom的数据源编写文档(数据源管理页面会呈现出来)

requestBody的格式是怎样的

requestBody原本是设计在requestParams字段中的,因为不想同时支持Get请求和Post请求,故要求所有的请求都为Post。于是废除了requestParams字段。既然废除了这个字段,requestBody应该代替其存在,并只需要实现其功能(我知道requestBody可以很复杂,但是我不想这么设计)

故requestBody有如下结构:


{
    "": "",
    "": "Boolean",
    "": "Integer"
}

对数组、对象的支持,我暂时不不考虑的,但是我很清楚的知道,我们的这套系统是可以非常简单的实现这个的。

wordId字段如何理解

我们不确定表单设计器、数据源管理是否只是国内用户使用。所以我们必须考虑国际化的问题。我解决国际化的问题还是通过名词表(我们在游戏行业中就是使用的这种方案,感觉很简单,但是很强大)。所以,我没有在数据库中直接存在datasourceName字段,而是存储了worldId。但是我可以很明确的告诉你,用户在添加一个表单的时候,是有数据源名称这个字段的,且这个字段就是存在datasourceName字段里的。


我会直接往名词表查一条记录。

下面展示的是名词表的设计,及相关记录的样式,具体的查询SQL我就不呈现了:

![2021-05-16-10-51-20](https://junjie2018sz.oss-cn-shenzhen.aliyuncs.com/images/2021-05-16-10-51-20.png)

id:1000
language:
{
“cn”: “中国”,
“us”: “美国”
}


~~~名词表很简单,我不会开文档单独说明了,~~~值得一提的是每增加对一个国家的支持,我们就需要为所有记录的language字段中增加一个国家。

思路已经清晰了,那我们的接口如何出数据了?先想清楚我们会在哪里出数据:

1. 数据源管理页的list接口
2. 表单设计器页为组件绑定数据源时的list接口(其实就是和上面一个接口)
3. 数据源编辑页

这个地方我也不想讲的太细了,需要记住的是,这一套动态表单的所有接口我们都要求用户传递language值,有了这个值,我们完全可以在返回的数据源接口中,完成worldId到datasourceName的转换。

## returnType为何要设计的这么复杂

为什么returnType要设计的这么复杂呢?因为我想在表单设计器中实现一些静态检查。

如何理解这个静态检查呢?我先举一个例子,组件需要一个返回值类型为BooleanList的数据源,拿到这个数据源后,组件不会去判断是否为BooleanList,它会直接遍历每个值,然后进行if判断。

如果我们不支持BooleanList、不支持在表单设计时进行的静态检查,用户在设计表单的时候,就可以将任意一个返回值为List的数据源绑定到该组件上。那么当这个组件运行的时候,它还是会假设自己获取的是一个BooleanList,如果这个时候进行了if判断,那么组件的行为完全可能是错误的。即使我们的组件检查了数据源返回的List是不是一个BooleanList,结果发现不是,又该怎么办,终止提供服务么(实际上我个人是比较推崇在拥有静态检查后,仍然检查是否为BooleanList,防止开发人员直接改库,造成组件行为错误问题)。这样做,其实就是典型的将静态检查挪到了运行时检查,只是在我们的场景中没有测试的高覆盖率测试,而是真正的表单用户来帮我们检查。

## ReturnType中Custome需要注意的问题

为什么会有这种类型的存在,显然是为了支持高级组件的数据源需求。有的组件可能想一次性扒拉下来所有的数据,然后自己缓存起来,进行处理,比如在一个组件内实现三级联动,我们就是使用Custom类型实现对这种需求的支撑。

有个问题提前讨论一下,数据源这个东西的RequestBody一定需要指定么?显然是不需要的啊,如果一个组件高度定制,就是那种前后端手拉手开发出来的组件,他们也没打算让其他人用。前端要的就是数据源提供一个url,甚至数据源都不需要,直接写死在组件的代码中,这个时候数据源有意义么,数据源的参数有意义么,没有意义的。

但是,有些问题必须要搞明白,一旦你的代码组件化了,放入到了组件库中,我们就没有办法控制用户在哪块使用你的组件。我是不会做任何设计来提供这种限制效果的(我未来最多做一个租户间的限制),我觉得违背了我的初心,没有任何意义。用户今天可能在一个表单中使用了你的组件,明天又到另一个组件中去使用你的组件。你的组件需要确保对表单的上下文没有任何依赖,你不能从表单上下文中获取任何值。当然,如果你有需求的化,可以考虑在组件的params区域声明你的需求,让用户给你绑定一个context中的数据。

## 能不能不过度设计,而是依靠高覆盖的测试

动态表单是产品、运营人员实时使用的,使用后将直接在用户端生效,测试无法及时接入。所以,表单设计器进行的必要的静态检查是一定需要的。