一、流程變數
流程例項按步驟執行時,需要儲存並使用一些資料,在Flowable中,這些資料稱為變數(variable)。
流程例項可以持有變數,稱作流程變數(process variables)。
為了使用效率,Flowable將變數分為兩種:執行時變數、歷史變數。
1.1 執行時變數
流程例項執行時的變數,存入act_ru_variable表中。在流程例項執行結束時,此例項的變數在表中刪除。
在流程例項建立及啟動時,可設定流程變數。所有的startProcessInstanceXXX方法都有一個可選引數用於設定變數。例如,在RuntimeService中:
ProcessInstance startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables);
也可以在流程執行中加入變數。例如,(RuntimeService):
void setVariable(String executionId, String variableName, Object value);
void setVariableLocal(String executionId, String variableName, Object value);
void setVariables(String executionId, Map<String, ? extends Object> variables);
void setVariablesLocal(String executionId, Map<String, ? extends Object> variables);
讀取變數方法(請注意TaskService中有類似的方法。這意味著任務與執行一樣,可以持有區域性變數,其生存期為任務持續的時間。)
Map<String, Object> getVariables(String executionId);
Map<String, Object> getVariablesLocal(String executionId);
Map<String, Object> getVariables(String executionId, Collection<String> variableNames);
Map<String, Object> getVariablesLocal(String executionId, Collection<String> variableNames);
Object getVariable(String executionId, String variableName);
<T> T getVariable(String executionId, String variableName, Class<T> variableClass);
注意:由於流程例項結束時,對應在執行時表的資料跟著被刪除。所以,查詢一個已經完結流程例項的變數,只能在歷史變數表中查詢。
1.2 歷史變數
歷史變數,存入act_hi_varinst表中。在流程啟動時,流程變數會同時存入歷史變數表中;在流程結束時,歷史表中的變數仍然存在。可理解為“永久代”的流程變數。
獲取已完成的、id為’XXX’的流程例項中,所有的HistoricVariableInstances(歷史變數例項),並以變數名排序。
historyService.createHistoricVariableInstanceQuery()
.processInstanceId("XXX")
.orderByVariableName.desc()
.list();
二、表單
在實際業務中,流程伴隨著各種各樣的表單,Flowable引擎將表單資料統一作為流程變數存入變數表中。所以,對於Flowable引擎,可以完全獨立於表單執行,因為可以用流程變數替代表單資料。
但一般的,我們需要結構化的資料,表單仍然是我們推薦的用法。
表單定義有兩種方法,內建表單和外部表單。
2.1 內建表單
以請假為例,XML內容:
<process id="leave" name="請假流程-內建表單">
<startEvent id="start">
<extensionElements>
<flowable:formProperty id="startDate" name="請假開始事件" type="date"
datePattern="dd-MMM-yyyy" required="true" readable="true" writeable="true"/>
<flowable:formProperty id="endDate" name="請假結束事件" type="date"
datePattern="dd-MMM-yyyy" required="true" readable="true" writeable="true"/>
<flowable:formProperty id="reason" name="請假原因" type="string"
required="true" readable="true" writeable="true"/>
<flowable:formProperty id="leaveType" type="enum" name="請假型別">
<flowable:value id="personalLeave" name="事假" />
<flowable:value id="annualLeave" name="年假" />
</flowable:formProperty>
</extensionElements>
</startEvent>
</process>
使用方法:
StartFormData FormService.getStartFormData(String processDefinitionId)
或
TaskFormData FormService.getTaskFormData(String taskId)
內建表單瞭解即可,實際應用更多的是使用外部表單。
2.2 外部表單
根據表單檔案自行渲染的任務表單,稱為外部表單。
2.2.1 XML內容
<process id="leave" name="請假流程-內建表單">
<startEvent id="start" flowable:formKey="form1"></startEvent>
</process>
注意:flowable:formKey="form1"中的"form1"對應表單定義檔案的"key"值。
2.2.2 表單定義
- 表單定義檔案的字尾為.form。
- 表單的JSON定義以key、name和description開頭。
- 表單引擎通過屬性key來辨別表單在整個表單引擎中的唯一身份。對於來源相同的同一個表單定義的版本系統也是基於屬性key運作的。
- 第二部分是一個陣列型別fields,表單定義的欄位在這裡闡明。
- 第三部分是可選的,用來定義表單的結果outcomes。示例如下:
{
"key": "form1",
"name": "My first form",
"fields": [
{
"id": "input1",
"name": "Input1",
"type": "text",
"required": false,
"placeholder": "empty"
}
],
"outcomes": [
{
"id": "null",
"name": "Accept"
},
{
"id": "null",
"name": "Reject"
}
]
}
2.2.3 部署表單
在springboot環境下,resources/forms目錄下任何.form字尾的表單定義檔案都會被自動部署。
例如,將2.2.2表單定義內容儲存為leave.form檔案,放入resources/forms目錄下。
注意:實際應用中,應當讓前端流程設計器生成指定格式的表單定義檔案,通過與前文提到的介面方式,更新部署流程定義及表單定義資源。
2.2.4 獲取及提交表單引數
實際上,渲染表單所需的所有資料都組裝在下面兩個方法:
StartFormData FormService.getStartFormData(String processDefinitionId)
TaskFormdata FormService.getTaskFormData(String taskId)
可以通過下面兩個方法提交表單引數:
ProcessInstance FormService.submitStartFormData(String processDefinitionId, Map<String,String> properties)
void FormService.submitTaskFormData(String taskId, Map<String,String> properties)
表單引數FormProperty的具體資訊:
public interface FormProperty {
/**
* 在{@link FormService#submitStartFormData(String, java.util.Map)}
* 或{@link FormService#submitTaskFormData(String, java.util.Map)}
* 中提交引數時使用的key
*/
String getId();
/** 顯示標籤 */
String getName();
/** 在本介面中定義的型別,例如{@link #TYPE_STRING} */
FormType getType();
/** 可選。這個引數需要顯示的值 */
String getValue();
/** 這個引數是否可以讀取:在表單中顯示,並可通過
* {@link FormService#getStartFormData(String)}
* 與{@link FormService#getTaskFormData(String)}
* 方法訪問。
*/
boolean isReadable();
/** 使用者提交表單時是否可以包含這個引數? */
boolean isWritable();
/** 輸入框中是否必填這個引數 */
boolean isRequired();
}
2.2.5 獲取及提交表單資料
獲取指定流程例項的表單資料的方法:
FormModel RuntimeService.getStartFormModel(String processDefinitionId, String processInstanceId);
提交表單資料的方法:
// 附帶表單資料啟動流程例項
ProcessInstance RuntimeService.startProcessInstanceWithForm(String processDefinitionId, String outcome, Map<String,Object> properties, String taskName);
// 附帶表單資料完成任務
void TaskService.completeTaskWithForm(String taskId, String formDefinitionId, String outcome, Map<String,Object> properties);
表單資料實際存放在流程變數表,所以,用流程變數的方法同樣可以獲取及提交表單資料。
2.3 表單型別欄位
表單支援以下型別欄位
- text: 文字欄位
- multi-line-text: 多行文字欄位
- integer: 文字欄位,但是隻允許數字型別的值
- boolean: 核取方塊欄位
- date: 日期欄位
- dropdown: 選擇框欄位,定義欄位時可以設定選項的值
- radio-buttons: 單選欄位,定義欄位時可以設定選項的值
- people: 選擇框欄位,可以選中使用者表裡的一個使用者
- functional-group: 選擇框欄位,可以選中分組表裡的一個組
- upload: 上傳檔案欄位
- expression: 一個標籤,在標籤文字中你可以運用JUEL表示式操作變數或其他動態的值
2.4 自定義表單欄位型別
在實際應用中,Flowable提供的表單欄位型別並不能完全滿足需求,往往我們需要自定義表單欄位型別。
所有自定義欄位型別需要繼承一個表達型別抽象類“org.flowable.engine.form.AbstractFormType”。
比如,定義一個"卡片"自定義型別:
public class CardFormType extends AbstractFormType {
// 定義表單型別的識別符號
@Override
public String getName() {
return "card";
}
// 把表單中的值轉換為實際的物件(實際處理邏輯根據具體業務而定)
@Override
public Object convertFormValueToModelValue(String propertyValue) {
return propertyValue;
}
// 把實際物件的值轉換為表單中的值(實際處理邏輯根據具體業務而定)
@Override
public String convertModelValueToFormValue(Object modelValue) {
return (String) modelValue;
}
}
新建配置類,註冊自定義欄位型別解析類
@Configuration
public class ApplicationConfig extends WebMvcConfigurerAdapter {
@Bean
public BeanPostProcessor activitiConfigurer() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof SpringProcessEngineConfiguration) {
List<AbstractFormType> customFormTypes = Arrays.<AbstractFormType>asList(new CardFormType());
((SpringProcessEngineConfiguration)bean).setCustomFormTypes(customFormTypes);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
};
}
}
2.5 自定義表單引擎
Flowable支援自定義表單引擎以適應各種場景。只需要實現介面org.flowable.engine.impl.form.FormEngine,然後在引擎中註冊自定義的表單引擎實現類即可。
public class MyFormEngine implements FormEngine {
// 表單引擎的名稱
@Override
public String getName() {
return "MyFormEngine";
}
// 實際處理邏輯根據具體業務而定
@Override
public Object renderStartForm(StartFormData startFormData) {
return "MyStartData";
}
// 實際處理邏輯根據具體業務而定
@Override
public Object renderTaskForm(TaskFormData taskFormData) {
return "MyTaskData";
}
}
註冊方法與自定義表單欄位型別相似,在配置類中加入以下語句:
List<FormEngine> customFormEngines = Arrays.<FormEngine>asList(new MyFormEngine());
((SpringProcessEngineConfiguration)bean).setCustomFormEngines(customFormEngines);
使用方法:
Object FormService.getRenderedStartForm(String processDefinitionId, "myFormEngine");
Object FormService.getRenderedTaskForm(String taskId);
三、小結
通過本篇,我們瞭解到了表單和流程變數的具體使用,同樣的,在實際業務使用中,還需要不少優化。比如,我們可以在formKey中儲存通用的key,通過演算法或轉換得到實際需要使用的表單模板,在普通螢幕尺寸的Web應用中顯示一個表單,在手機等小螢幕中顯示另一個表單。還有下一篇將講到的“整合JPA”,進一步對錶單和流程變數的使用做出優化。