有小伙伴在星球上催了好幾次了,今天松哥就來和大家聊一聊流程中的表單。
1. 表單分類
整體上來說,我們可以將表單分為三種不同的類型:
動態(tài)表單:這種表單定義方式我們可以配置表單中每一個字段的可讀性、可寫性、是否必填等信息,不過不能定義完整的表單頁面。
外置表單:外置表單我們只需要定義一下表單的 key,至于這個 key 對應的表單是什么樣子,則由開發(fā)者自己去維護。
內(nèi)置表單:這是內(nèi)置的表單定義以及渲染引擎,松哥在之前的一個不用寫代碼的案例,來看看Flowable到底給我們提供了哪些功能?一文中所使用的表單,就是這種。
另外小伙伴們需要注意,F(xiàn)lowable 中有很多不同類型的節(jié)點,但是只有開始節(jié)點和任務(wù)節(jié)點是支持表單定義的,其他節(jié)點均不支持表單定義。
2. 動態(tài)表單
今天我們就先來看看動態(tài)表單的玩法。
假設(shè)我有如下一個請假流程:

在第一個任務(wù)節(jié)點中,需要填寫請假的基本信息,那么我們選中該節(jié)點,然后點擊動態(tài)表單屬性,如下圖:

然后就可以開啟動態(tài)表單屬性的配置了:

我這里一共配置了四個屬性,這些屬性的含義應該都好理解,我就不一一贅述了。
接下來我們來下載這個流程圖。
流程的 XML 文件下載下來之后,我們可以在看到在 UserTask 節(jié)點中多了 flowable:formProperty 標簽,現(xiàn)在,如果我想將 UserTask 節(jié)點中的動態(tài)表單屬性拷貝到啟動節(jié)點中,直接拷貝即可,如下:
<process id="FormDemo01" name="FormDemo01" isExecutable="true">
<documentation>FormDemo01</documentation>
<startEvent id="startEvent1" flowable:formFieldValidation="true">
<extensionElements>
<flowable:formProperty id="startTime" name="請假開始時間" type="date" datePattern="yyyy-MM-dd HH:mm" required="true"></flowable:formProperty>
<flowable:formProperty id="endTime" name="請假結(jié)束時間" type="date" datePattern="yyyy-MM-dd HH:mm" required="true"></flowable:formProperty>
<flowable:formProperty id="reason" name="請假理由" type="string" required="true"></flowable:formProperty>
<flowable:formProperty id="days" name="請假天數(shù)" type="long" required="true"></flowable:formProperty>
</extensionElements>
</startEvent>
<userTask id="sid-F4DE03F1-D09F-4527-9267-0E5C276D08B8" name="提交請假申請" flowable:formFieldValidation="true">
<extensionElements>
<flowable:formProperty id="startTime" name="請假開始時間" type="date" datePattern="yyyy-MM-dd HH:mm" required="true"></flowable:formProperty>
<flowable:formProperty id="endTime" name="請假結(jié)束時間" type="date" datePattern="yyyy-MM-dd HH:mm" required="true"></flowable:formProperty>
<flowable:formProperty id="reason" name="請假理由" type="string" required="true"></flowable:formProperty>
<flowable:formProperty id="days" name="請假天數(shù)" type="long" required="true"></flowable:formProperty>
</extensionElements>
</userTask>
<sequenceFlow id="sid-2A8D19F2-927C-4FCE-AF31-534425B1CA18" sourceRef="startEvent1" targetRef="sid-F4DE03F1-D09F-4527-9267-0E5C276D08B8"></sequenceFlow>
<userTask id="sid-9136F312-F00B-467E-A61B-F2932BA9068A" name="請假審批" flowable:formFieldValidation="true"></userTask>
<sequenceFlow id="sid-877A95AB-B8A4-47FE-BC9F-0998FEAEC52C" sourceRef="sid-F4DE03F1-D09F-4527-9267-0E5C276D08B8" targetRef="sid-9136F312-F00B-467E-A61B-F2932BA9068A"></sequenceFlow>
<endEvent id="sid-E26593D4-C67B-4784-98EE-772B9659F805"></endEvent>
<sequenceFlow id="sid-1A5C4E8C-6705-4148-A0E3-E7769631BFD9" sourceRef="sid-9136F312-F00B-467E-A61B-F2932BA9068A" targetRef="sid-E26593D4-C67B-4784-98EE-772B9659F805"></sequenceFlow>
</process>
可以看到,在 startEvent? 和第一個 userTask? 中都有 flowable:formProperty 標簽。
接下來,按照我們之前所講的,我們來部署一下這個流程。部署完成之后,我們可以通過如下方式來查詢流程中的動態(tài)表單信息:
@Autowired
FormService formService;
@Test
void test01(){
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey("FormDemo01").latestVersion().singleResult();
StartFormData startFormData = formService.getStartFormData(pd.getId());
System.out.println("startFormData.getDeploymentId() = " + startFormData.getDeploymentId());
System.out.println("startFormData.getFormKey() = " + startFormData.getFormKey());
List<FormProperty> formProperties = startFormData.getFormProperties();
for (FormProperty fp : formProperties) {
String value = fp.getValue();
String id = fp.getId();
boolean readable = fp.isReadable();
boolean writable = fp.isWritable();
boolean required = fp.isRequired();
String name = fp.getName();
FormType type = fp.getType();
String key = "";
if (type instanceof EnumFormType) {
key = "values";
} else if (type instanceof DateFormType) {
key = "datePattern";
}
Object information = type.getInformation(key);
logger.info("value:{},id:{},readable:{},writeable:{},required:{},name:{},info:{}", value, id, readable, writable, required, name, information);
}
}
小伙伴們可以看到,這個查詢是通過流程定義查詢的,所以這里查詢到的信息,其實也是和流程實例無關(guān)的。只是單純的查看一下啟動節(jié)點上有哪些動態(tài)表單需要輸入,以及這些動態(tài)表單的類型。最終輸出日志如下:

3. 啟動帶表單的實例
動態(tài)表單,其實跟普通的變量有點像,啟動的時候我們可以通過表單服務(wù)類來啟動,代碼如下:
@Test
void test02(){
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionKey("FormDemo01").latestVersion().singleResult();
Map<String, String> vars = new HashMap<>();
vars.put("startTime", "2022-10-10 10:10");
vars.put("endTime", "2022-10-12 10:10");
vars.put("reason", "玩兩天");
vars.put("days", "3");
ProcessInstance pi = formService.submitStartFormData(pd.getId(), vars);
}
小伙伴們看到,我們這里通過 formService.submitStartFormData 方法來啟動流程實例,啟動的時候,傳入了 vars 變量。
流程實例啟動成功之后,我們在 ACT_RU_VARIABLE 表中就可以看到這些動態(tài)表單的信息。

從這里可以看到我們剛剛存入的數(shù)據(jù)。
4. 查詢?nèi)蝿?wù)上的表單
現(xiàn)在我們的流程走到了 提交請假申請? 這一步了,我們在繪制流程圖的時候,提交請假申請? 這個 UserTask 中也是有動態(tài)表單的,前面啟動流程時傳遞的動態(tài)表單信息,現(xiàn)在已經(jīng)傳到 提交請假申請 這一步了,我們可以通過如下方式來進行查詢:
@Test
void test03(){
Task task = taskService.createTaskQuery().singleResult();
TaskFormData taskFormData = formService.getTaskFormData(task.getId());
List<FormProperty> formProperties = taskFormData.getFormProperties();
for (FormProperty fp : formProperties) {
String value = fp.getValue();
String id = fp.getId();
boolean readable = fp.isReadable();
boolean writable = fp.isWritable();
boolean required = fp.isRequired();
String name = fp.getName();
FormType type = fp.getType();
String key = "";
if (type instanceof EnumFormType) {
key = "values";
} else if (type instanceof DateFormType) {
key = "datePattern";
}
Object information = type.getInformation(key);
logger.info("value:{},id:{},readable:{},writeable:{},required:{},name:{},info:{}", value, id, readable, writable, required, name, information);
}
}
小伙伴們看到,調(diào)用 formService.getTaskFormData 方法傳入 TaskId 即可進行查詢。這個時候查詢出來的內(nèi)容就有值了:

可能有的小伙伴會說,這跟用變量有啥區(qū)別呀,用變量不也是這樣嗎?
變量是散的,而表單是整的。
在上面的代碼中,一個方法就可以提取出來所有的表單信息了,然后就遍歷就行了。
另外還需要注意,如果 提交請假申請? 中的動態(tài)表單和啟動節(jié)點的動態(tài)表單不一致的話,提交請假申請 節(jié)點中有哪些動態(tài)表單,就能拿到哪些數(shù)據(jù),其他的數(shù)據(jù)就不能通過表單拿到。
以上面的案例來說,startEvent 中有 startTime、endTime、reason 以及 days 四個動態(tài)表單屬性,如果 提交請假申請 中只有 reason 和 days 兩個動態(tài)表單屬性的話,那么就只能獲取這兩個動態(tài)表單屬性,其他的動態(tài)表單屬性則可以通過變量去獲取。
5. 保存與完成
對于 UserTask 上的表單,我們首先可以通過如下方式來提交表單數(shù)據(jù):
@Test
void test04(){
Task task = taskService.createTaskQuery().singleResult();
Map<String, String> vars = new HashMap<>();
vars.put("startTime", "2022-10-11 11:11");
vars.put("endTime", "2022-10-19 11:11");
formService.saveFormData(task.getId(), vars);
}
這個方法只是保存動態(tài)表單變量,并不會完成當前 Task。
如果想在提交表單變量的同時順便完成當前 UserTask,方式如下:
@Test
void test04(){
Task task = taskService.createTaskQuery().singleResult();
Map<String, String> vars = new HashMap<>();
vars.put("startTime", "2022-10-11 11:11");
vars.put("endTime", "2022-10-19 11:11");
formService.submitTaskFormData(task.getId(), vars);
}
該方法在提交表單變量的同時,還會順便 complete 當前 UserTask。
好啦,這就是關(guān)于動態(tài)表單松哥和大家介紹的內(nèi)容啦~
動態(tài)表單用法簡單,很多小伙伴想不明白為什么要用表單,用變量不行嗎?技術(shù)上來說,變量當然可以,但是變量是一個一個的,是零散的,而表單是整的,整存整取的。