天天看點

工作流Activiti架構中表單的使用!詳細解析内置表單和外置表單的渲染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表單模版