在很多业务流程应用中,业务审批单的样式、内容多变,然而系统对业务表单数据并不敏感,因此,不使用对应的关系型数据表,而采用NoSQL技术来优化设计。因为NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。按NoSQL的特性,可以灵活进行schema结构(列定义)的修改,理论上应该可以很好支持这些多样表单的持久化保存。基于上述原因,业务审批单采用网页表单文档设计。
网页表单设计
首先,我们看一看在HTML表单元素(对象)中使用自定义属性的示例:
<input fieldid="name" fieldtype="char" size=50>名称</input><br>
通过自定义属性“fieldtype”来定义数据类型。<br>
<input fieldid="old" fieldtype="number" size=20 value="42">年龄</input><br>
网页表单数据字段定义
为了避免浏览器兼容性问题,通过自定义属性的方式来定义表单文档数据项,定义规则如下:
属性名称 | 作用说明 | 备注 |
---|---|---|
fieldid | 数据字段名称 | 避免与id冲突,单独命名 |
fieldtype | 数据字段类型 | 支持主流number、text、datetime等 |
fieldsize | 字段长度 | 主要是定义number、text等长度 |
fieldname | 字段名称 | 定义中文名称 |
subtable | 子表的列数 | 适用于嵌套多行子表结构,在table控件中定义 |
subid | 子表的列名定义 | 适用于嵌套多行子表结构 |
对应JSON数据格式如下:
{数据字段名称1:value1,数据字段名称2:value2,数据字段名称n
:valuen}
网页表单数据选择列表的数据定义
待续…
主从结构,动态增加数据行
如图所示,在HTML文档中,表单中一对多的从表(多行输入数据的table)定义如下:
<button id="testtable" type="button" onclick="insertRow()">测试插入一行</button><br>
<table id="dynamictable" fieldid="subdatas" subtable="3" border="1" cellspacing="0" width="400">
<tr>
<td>数据名称</td><td>数据类型</td><td>数值</td>
</tr>
<tr>
<td><input type="text" subid="fieldid" subcol=0 name="fieldid" size=50></td>
<td><input type="text" subid="fieldtype" subcol=1 name="fieldtype" size=20></td>
<td><input type="text" subid="fieldvalue" subcol=2 name="fieldvalue" size=20></td>
</tr>
</table>
使用JavaScript技术实现的动态添加一行的代码如下:
//定义插入一行表格的函数
function insertRow(){
var dytb_id = ‘dynamictable‘;
var dy_row_num = document.getElementById(dytb_id).rows.length;
//取table中第二行单元格集合
var dy_row = document.getElementById(dytb_id).rows[1].cells;
//在table末尾,追加一行
var dytb=document.getElementById(dytb_id).insertRow(dy_row_num);
for (i = 0;i<dy_row.length; i++){
var dy_td = dytb.insertCell(i);
dy_td.innerHTML = dy_row[i].innerHTML;
}
}
通过上面示例,在表单文档设计中,需要定义规则如下:
- 动态增加行首先定义表头,再定义出一行输入控件;
- 增加行的识别定义,用以确认是从表多行数据;
- 每个单元格的定义,与表单数据字段定义方式一样。
网页表单解析
虽然通过网页文档做为审批表单,但也需要支持简捷的数据识别和简易的统计查询,这里采用MongoDB数据库做为底层数据库支撑。
解析目的及用处:
- 解析文档中的数据字段及数值,并形成JSON数据;
- 在文档中定义数据字段、业务规则,用以与流程衔接,需要解析定义;
- 在文档中的定义,避开关系型数据复杂的管理,此模型可以追溯早期Lotus Notes/Domino数据库模型。
文档解析方式为通过遍历方式解析表单,表单数据形式涉及到单表及主从结构。而且,需要表单快速开发工具支撑。
网页表单定义解析
网页表单定义解析主要用于获取表单数据模型,用以为数据统计分析模型提供服务,形成数据接口模型。
网页表单业务数据解析
演示界面如下图所示。
HTML文档定义如下:
<body>
<h1>表单元素遍历测试 JavaScript</h1>
<p id="demo" >这是表单数据解析示例.</p>
<div>
<input id="name" fieldtype="char">名称</input><br>
通过自定义属性“fieldtype”来定义数据类型。<br><br>
<button id="testtable" type="button" onclick="insertRow()">测试插入一行</button>  
<button id="test" type="button" onclick="getallelem()">测试解析表单数据</button><br><br>
<input fieldid="title" fieldtype="text" value="测试申请单" size=100>标题</input><br>
<input fieldid="old" fieldtype="number" value="42" size=100>年龄</input><br>
多行子表单,字段属性定义为“subid”,表单按数据字段属性定义,标识出含有子表,属性为“subtable”单独定义列数,其他不变。
<table id="dynamictable" fieldid="subdatas" subtable="3" border="1" cellspacing="0" width="400">
<tr>
<td>数据名称</td><td>数据类型</td><td>数值</td>
</tr>
<tr>
<td><input type="text" subid="fieldid" subcol=0 name="fieldid" size=50></td>
<td><input type="text" subid="fieldtype" subcol=1 name="fieldtype" size=20></td>
<td><input type="text" subid="fieldvalue" subcol=2 name="fieldvalue" size=20></td>
</tr>
</table>
<br><input fieldid="flag" fieldtype="text" value="end" size=100>结束标志</input><br>
</div>
</body>
提取表单数据到JSON格式字符串的JavaScript函数如下所示:
function getallelem(){
var elems = document.getElementsByTagName("*");
var ret_json = ""; //定义返回JSON数据字符串
var n = 0; //JSON数据起点
var m = 0; //JSON嵌套子文档起点
var subcolumns = 0; //多行表单列数
var subrows = 0; //多行表单数据行数
var row_num = 1; //默认是一行数据
for(var i=0;i<elems.length;i++){
if (elems[i].hasAttribute("fieldid") && !(elems[i].hasAttribute("subtable"))){
if (n == 0){
ret_json += "\"" +elems[i].getAttribute("fieldid") + "\":\"" + elems[i].value + "\"";
}else{
ret_json += ",\"" + elems[i].getAttribute("fieldid") + "\":\"" + elems[i].value + "\"";
}
n++;
}else{
if (elems[i].hasAttribute("subtable")){
subcolumns = elems[i].getAttribute("subtable");
var tbl_id = elems[i].id;
//取表单数据行数
subrows = document.getElementById(tbl_id).rows.length - 1;
ret_json += "\",\"" + elems[i].getAttribute("fieldid") + "\":[{\"";
m = 0;
}else{
if (elems[i].hasAttribute("subid") && (m < subcolumns)){
if (m == 0){
ret_json += elems[i].getAttribute("subid") + "\":\"" + elems[i].value + "\"";
}else{
ret_json += ",\"" + elems[i].getAttribute("subid") + "\":\"" + elems[i].value + "\"";
}
m++;
}else{
if (elems[i].hasAttribute("subid")){
ret_json += "},{\"" + elems[i].getAttribute("subid") + "\":\"" + elems[i].value + "\"";
m = 1;
row_num++;
}
}
if ((row_num == subrows) && (row_num>0) && (m == subcolumns)){
ret_json += "}]";
m=0,row_num=0;
}
}
}
}
alert("{" + ret_json + "}");
}
网页表单文档存储
保存操作及事务处理
在保存网页表单文档操作中,需要把文档存储到MongoDB、和关系型数据库,二者不在一个事务中。因此,可以使用Cordys平台自动流程模型进行事务管理。
Created with Rapha?l 2.1.2函数函数HTMLHTML事务管理流程事务管理流程存储MongoDB环节存储MongoDB环节存储业务实例环节存储业务实例环节解析HTML文档()生成JSON数据()启动流程()调用存储表单数据Webservice()调用存储业务实例数据Webservice()
保存操作及非事务管理方式
Created with Rapha?l 2.1.2函数函数HTMLHTML非事务管理非事务管理存储MongoDB环节存储MongoDB环节存储业务实例环节存储业务实例环节解析HTML文档()生成JSON数据()保存文档操作()调用存储表单数据Webservice()调用存储业务实例数据Webservice()回写保存完毕Webservice()
由于作者水平有限,欢迎反馈交流。
参考:
JavaScript遍历HTML表单元素及表单定义 肖永威 2015.5
Cordys BOP 4平台开发实战——MongoDB提供文档服务(1) 肖永威 2015.4