工作流Activiti框架中表單的使用!詳細解析內置表單和外置表單的渲染
Activiti中的表單
- Activiti提供了一種方便而且靈活的方式在業務流程中以手工方式添加表單
- 對錶單的支援有2種方式:
- 通過表單屬性對內置表單進行渲染
- 通過表單屬性對外置表單進行渲染
表單屬性
- 業務流程相關聯的所有資訊:
- 包含自身的流程變數
- 通過流程變數的引用
- Activiti支援存儲複雜的Java對象作為流程變數:
- 序列化對象
- Jpa實體對象
- 整個XML文檔作為字元串
- 用戶是在啟動一個流程和完成用戶任務時,與流程進行交互
- 表單需要某個UI技術渲染之後才能夠與用戶進行交互
- 為了能夠使用不同UI技術變得容易,流程定義包含一個對流程變數中複雜的Java類型對象到一個properties的Map<String,String> 類型的轉換邏輯
- 使用Activiti API的方法查看公開的屬性資訊.然後,任意UI技術都能夠在這些屬性上面構建一個表單.該屬性專門為流程變數提供了一個視圖. 表單所需要顯示的屬性可以返回值FormData中獲取:
StartFormData FormService.getStartFormData(String processDefinitionId)
或者
TaskFormdata FormService.getTaskFormData(String taskId)
- 在默認情況下,內置的表單引擎遇到這些變數就像對待流程變數一樣.如果任務表單屬性和流程變數是一對一的關係,那麼任務表單屬性就不需要進行申明了:
<startEvent id="start" />
- 當執行到開始事件時,所有的流程變數都是可用的,但是
formService.getStartFormData(String processDefinitionId).getFormProperties()
會是一個空值,因為沒有定義一個具體的映射
- 表單中所有被提交的屬性都將會作為流程變數被存儲在Activiti使用的資料庫中. 這意味著在一個表單中新添加一個簡單的input輸入欄位,也會作為一個新的變數被存儲
- 屬性來自於流程變數,但是不一定非要作為流程變數存儲:
- 一個流程變數可能是JPA實體如類Address.在某種UI技術中使用的表單屬性StreetName可能會關聯到一個表達式 #{address.street}
- 用戶提交的表單屬性應該作為流程變數進行存儲
- 使用UEL值表達式將其作為流程變數的一個嵌套屬性進行存儲
- 提交的表單屬性默認的行為是作為流程變數進行存儲,除非一個 formProperty 申明了其他的規則
- 類型轉換也可以應用於表單數據和流程變數之間的處理:
<userTask id="task">
<extensionElements>
<activiti:formProperty id="room" />
<activiti:formProperty id="duration" type="long"/>
<activiti:formProperty id="speaker" variable="SpeakerName" writable="false" />
<activiti:formProperty id="street" expression="#{address.street}" required="true" />
</extensionElements>
</userTask>
- 表單屬性room將會被映射為String類型流程變數room
- 表單屬性duration將會被映射為java.lang.Long類型流程變數duration
- 表單屬性speaker將會被映射為流程變數SpeakerName:
- writable=”false” 只能夠在TaskFormData對象中使用.如果屬性speaker提交,將會拋出一個ActivitiException的異常
- readable=”false” 該屬性就會在FormData進行排除,但是在提交後仍然會對其進行處理
- 表單屬性street將會映射為Java Bean address的屬性street作為String類型的流程變數:
- 當提交的表單屬性並沒有提供並且required=”true” 時,那麼就會拋出一個異常
- 表單數據也可以作為FormData的一部分提供類型元數據.該FormData可以從以下方法的返回值中獲取:
StartFormData FormService.getStartFormData(String processDefinitionId)
TaskFormdata FormService.getTaskFormData(String taskId)
- 表單屬性類型:
- string: org.activiti.engine.impl.form.StringFormType
- long: org.activiti.engine.impl.form.LongFormType
- enum: org.activiti.engine.impl.form.EnumFormType
- date: org.activiti.engine.impl.form.DateFormType
- boolean: org.activiti.engine.impl.form.BooleanFormType
- 對於聲明每一個表單屬性,FormProperty資訊可以通過以下方式獲取:
List<FormProperty> formService.getStartFormData(String processDefinitionId).getFormProperties()
或者
List<FormProperty> formService.getTaskFormData(String taskId).getFormProperties()
public interface FormProperty {
/**
the key used to submit the property in {@link FormService#submitStartFormData(String, java.util.Map)}
* or {@link FormService#submitTaskFormData(String, java.util.Map)} */
String getId();
/** the display label */
String getName();
/** one of the types defined in this interface like e.g. {@link #TYPE_STRING} */
FormType getType();
/** optional value that should be used to display in this property */
String getValue();
/** is this property read to be displayed in the form and made accessible with the methods
* {@link FormService#getStartFormData(String)} and {@link FormService#getTaskFormData(String)}. */
boolean isReadable();
/** is this property expected when a user submits the form? */
boolean isWritable();
/** is this property a required input field */
boolean isRequired();
}
- 示例:
<startEvent id="start">
<extensionElements>
<activiti:formProperty id="speaker"
name="Speaker"
variable="SpeakerName"
type="string" />
<activiti:formProperty id="start"
type="date"
datePattern="dd-MMM-yyyy" />
<activiti:formProperty id="direction" type="enum">
<activiti:value id="left" name="Go Left" />
<activiti:value id="right" name="Go Right" />
<activiti:value id="up" name="Go Up" />
<activiti:value id="down" name="Go Down" />
</activiti:formProperty>
</extensionElements>
</startEvent>
- 所有的表單屬性的資訊都是可以通過API進行訪問的:
- formProperty.getType().getName(): 獲取類型的名稱
- formProperty.getType().getInformation(“datePattern”): 獲取日期的匹配方式
- formProperty.getType().getInformation(“values”): 可以獲取到枚舉值
- Activiti控制台支援表單屬性並且可以根據表單定義對錶單進行渲染:
<startEvent ... >
<extensionElements>
<activiti:formProperty id="numberOfDays" name="Number of days" value="${numberOfDays}" type="long" required="true"/>
<activiti:formProperty id="startDate" name="First day of holiday (dd-MM-yyy)" value="${startDate}" datePattern="dd-MM-yyyy hh:mm" type="date" required="true" />
<activiti:formProperty id="vacationMotivation" name="Motivation" value="${vacationMotivation}" type="string" />
</extensionElements>
</userTask>
當使用Activiti控制台時,會被渲染成流程的啟動表單
外置表單的渲染
- Activiti中的API允許執行Activiti流程引擎之外的方式渲染任務表單,可以用自定義方式對任務表單進行渲染
- 所有需要渲染的表單屬性進行裝配的服務方法有兩種:
- StartFormData FormService.getStartFormData(String processDefinitionId)
- TaskFormdata FormService.getTaskFormData(String taskId)
- 表單屬性提交的兩種方式:
- ProcessInstance FormService.submitStartFormData(String processDefinitionId, Map<String,String> properties)
- void FormService.submitStartFormData(String taskId, Map<String,String> properties)
- 可以將任何錶單模版資源放進要部署的業務文檔之中(如果想要按照流程的版本進行存儲).將會在部署中作為一種可用的資源
- 獲取部署表單模版的方式有兩種:
- String ProcessDefinition.getDeploymentId()
- InputStream RepositoryService.getResourceAsStream(String deploymentId, String resourceName)
- 這樣就可以獲取表單模版定義文件,就可以在應用中渲染或者顯示錶單
- 也可以使用該功能獲取任務表單之外的其他的部署資源用於其他的目的
- 屬性 <userTask activiti:formKey=”…” 暴露方式API:
- String FormService.getStartFormData(String processDefinitionId).getFormKey()
- String FormService.getTaskFormData(String taskId).getFormKey()
- 可以使用這個存儲部署的模版中的全名(例如org/activiti/example/form/my-custom-form.xml) 但是這並不是必須的:
- 可以在表單屬性中存儲一個通用的key,然後運用一種演算法或者換轉去得到你實際使用的模版
- 當需要通過不同UI技術渲染不同的表單會更加方便:
- 使用正常螢幕大小的web應用程式的表單
- 移動手機小螢幕的表單
- IM表單
- email表單模版