表单字段继承体系(FormField / ValueStoreField)¶
位置:
obpm-core/.../runtime/dynaform/form/ejb/(73 个类)。本文讲**继承骨架与列生成机制**。基类体系见 [[entity-base-hierarchy]];.form文件 Schema 见 [[../../workspace-mechanism/schemas/form-file]]。
1. 继承骨架¶
动态表单的 40+ 字段类型不靠类爆炸,而靠**一个抽象基类 + 能力接口(capability interface)组合**:
classDiagram
class FormElement {
<<interface>>
}
class FormField {
<<abstract>>
#String name
#String fieldtype
+getOrderdValue()
}
class ValueStoreField {
<<interface>>
+getFieldtype() String
}
class IOptionsField {
<<interface>>
选项类字段能力
}
class InputField
class SelectField
class DateField
class RadioField
class AttachmentUploadToDataBaseField
class LabelField
FormElement <|.. FormField
FormField <|-- InputField
FormField <|-- SelectField
FormField <|-- DateField
FormField <|-- LabelField
FormField <|-- AttachmentUploadToDataBaseField
ValueStoreField <|.. InputField
ValueStoreField <|.. SelectField
ValueStoreField <|.. DateField
IOptionsField <|.. SelectField
核心角色¶
| 类/接口 | 职责 |
|---|---|
FormElement(接口) |
表单内一切元素的统一契约 |
FormField(抽象基类) |
全部字段的公共态:name(→ 动态表列名)、fieldtype(→ 列类型)、显隐/只读脚本引用、校验等。40+ 具体字段(InputField/SelectField/MapField/HTMLEditorField…)都直接继承它 |
ValueStoreField(接口) |
能力标记:"本字段要落库"。动态表建表时只问 instanceof ValueStoreField——实现它 → 生成 ITEM_{NAME} 列;不实现(如 LabelField 纯展示、IncludeField 包含)→ 不建列 |
IOptionsField(接口) |
选项类能力(Select/Radio/Checkbox),供视图筛选与联动取选项 |
这是典型的"继承管公共态、接口管能力"设计:字段的存储行为不放进继承树(否则 2^n 种组合爆炸),而由接口正交组合。
2. 列生成机制(字段 → TLK_ 列)¶
flowchart TD
A[表单保存<br/>FormDesignTimeService] --> B[FormTableProcessBean<br/>createOrUpdateDynaTable]
B --> C{遍历 fields<br/>instanceof ValueStoreField?}
C -->|是| D["列名 = ITEM_ + name 大写<br/>($开头无前缀)"]
C -->|否| E[跳过,不建列]
D --> F[fieldtype → JDBC 类型<br/>VARCHAR/NUMBER/DATE/TEXT/BLOB]
F --> G[ChangeLog 对比新旧结构]
G --> H["SQLBuilder(按 dbType 选库方言)<br/>Mysql*/Oracle*/PostgreSQL*…"]
H --> I[DDL 执行<br/>仅加列,不删列]
映射表单(type=65536)例外:列名由 mappingStr.columnMappings 指定,不走 ITEM_ 前缀。
3. 文档侧:Document / Item¶
字段定义"列",Document 承载"行":
classDiagram
class ValueObject {
实体基类(见基类篇)
}
class IDocument {
<<interface>>
}
class AbstractDocument {
<<abstract>>
}
class Document
class Item {
字段值容器:字段名→值
}
class Form {
定义侧(DesignTimeSerializable 线)
}
ValueObject <|-- AbstractDocument
IDocument <|.. AbstractDocument
AbstractDocument <|-- Document
Document "1" o-- "*" Item : items
Form ..> Document : 定义与实例分离
读写分工:Document/Item 属 ValueObject 线(运行时数据),Form 属 DesignTimeSerializable 线(设计定义)。AbstractDocument(document/model/)持有 getFirstNodeList() 等流程联动方法——文档创建后即知流程首节点,是表单与工作流的桥接点。AbstractDocStaticTblDAO 把 Document+Items 拆行写入 TLK_ 表(机制见 [[dao-process-mechanism]])。