Flowable實戰(五)表單和流程變量


一、流程變量

  流程實例按步驟執行時,需要保存並使用一些數據,在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”,進一步對表單和流程變量的使用做出優化。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM