一、選型分析
動態(tài)表單是一種要求比較靈活的使用場景,根據(jù)動態(tài)的模型來生成對應的表單,并且能夠很方便的隨時修改結構。
通過分析,整理了三種可能符合的方案。
1.MySQL物理表方案
每個模型對應生成一張MySQL物理表,并生成對應代碼,動態(tài)裝載到Spring。
此方案的優(yōu)點是:
a. 做到了代碼和數(shù)據(jù)的隔離,并且能很好的適應傳統(tǒng)框架。
b. 查詢統(tǒng)計比較方便
也有很多弊端:
a. 實現(xiàn)成本高,且需要解決運行時不停服新增表單對應的功能。
b. 變更不方便,每次結構變更需要修改物理表,并且重新生成對應的代碼。
2.MySQL邏輯表方案
一張基礎屬性表+一張表單結構表+一張數(shù)據(jù)大表

a. 通過基礎屬性表創(chuàng)建結構映射表。
b. 實際的數(shù)據(jù)存儲在大表中,字段對應到映射中的模型。
此方案的優(yōu)點:
a. 實現(xiàn)成本低,邏輯控制數(shù)據(jù)關系。
b. 非常輕松的隨時變更結構,只需要修改、刪除或新增記錄就可以實現(xiàn)效果。
缺點:
a. 不適合大量數(shù)據(jù)的操作,數(shù)據(jù)大表會極度膨脹。
b. 數(shù)據(jù)隔離性較差,做數(shù)據(jù)查詢和統(tǒng)計比較麻煩。
3.NoSQL物理表方案
結合前2種方案,我們試圖尋找一種既能做到數(shù)據(jù)隔離,也能方便后期隨時修改結構的方案。
通過NoSQL文檔類型數(shù)據(jù)庫來解決靈活變更結構且能保證數(shù)據(jù)表的隔離。
在這里,我們選擇的是MongoDB。下面,就按照這個思路展開詳細設計。
二、MongoDB物理表方案設計
1. 邏輯設計
結構采用MySQL來存儲維護,實際的數(shù)據(jù)采用MongoDB來存儲。
表單結構關系設計

組件元素表的每條記錄cell對應的是系統(tǒng)中支持的組件,包含了組件的類型、組件名稱等屬性。
字段對應到的是組件元素,這里可能是一個字段對應一個組件元素,也有可能是多個字段對應一個組件元素,因為組件元素有可能是復合組件,如身份信息組件等。
字段對應好后組合成字段集合,也就是實際的表單結構。

2.MongoDB表設計
公共字段設計
| 字段名 | 字段類型 | 備注 |
|---|---|---|
| _id | string | 默認字段,值根據(jù)uid生成,方便查詢和去重 |
| uid | string | 業(yè)務uid |
3.MongoDB操作API設計
因為表都是動態(tài)的,所以不適合用spring自帶的mongoDb cruid框架,對于輸入和輸出數(shù)據(jù)需要用json來表現(xiàn)。
項目中定義了 MongoDbTemplate操作類來對動態(tài)表操作數(shù)據(jù),具體方法如下:
/**
* 查詢記錄
* @param queryDTO
* @return
*/
public JSONArray queryData(DocumentQueryDTO queryDTO)
/**
* 查詢單條記錄
* @param collectionName
* @param uid
* @return
*/
public JSONObject selectOne(String collectionName, String uid)
/**
* 分頁查詢
* @param queryPageDTO
* @return
*/
public PageResult selectPage(DocumentQueryPageDTO queryPageDTO)
/**
* 單條記錄插入
* @param collectionName
* @param jsonObject
* @return
*/
public boolean insertOrUpdate(String collectionName, JSONObject jsonObject)
/**
* 批量插入
* @param collectionName
* @param jsonArray
* @return
*/
public boolean insertOrUpdateMany(String collectionName, JSONArray jsonArray)
/**
* 刪除文檔
* @param collectionName
* @param uid
* @return
*/
public boolean removeDocument(String collectionName, String uid)
/**
* 根據(jù)條件刪除
* @param collectionName
* @param filter
* @return
*/
public boolean removeDocumentByFilter(String collectionName, Bson filter)</pre>
查詢入?yún)ocumentQueryDTO類字段信息如下
@Data
public class DocumentQueryDTO implements Serializable {
private String collectionName;
/**
* 過濾條件
* com.mongodb.client.model.Filters類來構建條件
*/
private Bson filter;
/**
* 排序字段
*/
private SortParam sortParam;
}
SortParam類字段信息
@Data
public class SortParam {
/**
* 排序字段名
*/
private String sortKey;
/**
* 排序類型
* ASC 升序
* DESC 降序
*/
private SortEnum sort;
}
Filters使用
//單條件查詢
Bson filter = Filters.eq("uid", "123");
//多條件查詢
Bson filter = Filters.and(Filters.eq("uid", "123"), Filters.eq("age", 12));
//也可支持or、in等操作符。</pre>