工作流Activiti框架中表单的使用!详细解析内置表单和外置表单的渲染

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介: 本文介绍了工作流Activiti框架中表单的使用。在工作流Activiti框架中,支持在业务流程中添加内置表单和外置表单。详细说明了工作流中的表单需要具备的属性以及表单属性在工作流中的映射关系。最后介绍了工作流Activiti框架中对支持的表单的渲染方式。通过这篇文章,可以帮助我们在工作流Activiti框架中更加熟练地运用表单。

Activiti中的表单

  • Activiti提供了一种方便而且灵活的方式在业务流程中以手工方式添加表单
  • 对表单的支持有2种方式:

    • 通过表单属性对内置表单进行渲染
    • 通过表单属性对外置表单进行渲染

表单属性

  • 业务流程相关联的所有信息:

    • 包含自身的流程变量
    • 通过流程变量的引用
  • Activiti支持存储复杂的Java对象作为流程变量:

    • 序列化对象
    • Jpa实体对象
    • 整个XML文档作为字符串
  • 用户是在启动一个流程和完成用户任务时,与流程进行交互
  • 表单需要某个UI技术渲染之后才能够与用户进行交互
  • 为了能够使用不同UI技术变得容易,流程定义包含一个对流程变量中复杂的Java类型对象到一个propertiesMap<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表单模版
相关文章
|
2月前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
48 3
|
2月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
160 3
|
26天前
|
开发框架 Dart Android开发
安卓与iOS的跨平台开发:Flutter框架深度解析
在移动应用开发的海洋中,Flutter作为一艘灵活的帆船,正引领着开发者们驶向跨平台开发的新纪元。本文将揭开Flutter神秘的面纱,从其架构到核心特性,再到实际应用案例,我们将一同探索这个由谷歌打造的开源UI工具包如何让安卓与iOS应用开发变得更加高效而统一。你将看到,借助Flutter,打造精美、高性能的应用不再是难题,而是变成了一场创造性的旅程。
|
1月前
|
存储 Java 开发者
Java中的集合框架深入解析
【10月更文挑战第32天】本文旨在为读者揭开Java集合框架的神秘面纱,通过深入浅出的方式介绍其内部结构与运作机制。我们将从集合框架的设计哲学出发,探讨其如何影响我们的编程实践,并配以代码示例,展示如何在真实场景中应用这些知识。无论你是Java新手还是资深开发者,这篇文章都将为你提供新的视角和实用技巧。
32 0
|
2月前
|
分布式计算 Java 应用服务中间件
NettyIO框架的深度技术解析与实战
【10月更文挑战第13天】Netty是一个异步事件驱动的网络应用程序框架,由JBOSS提供,现已成为Github上的独立项目。
55 0
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
2月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
76 0
|
2月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
62 0
|
2月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
66 0
|
2月前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
86 0

推荐镜像

更多
下一篇
DataWorks