工作流基础操作 FormService

使用

FormService formService = processEngine.getFormService();
Activiti 中 FormService 的作用与核心方法
**
在 Activiti 工作流中,FormService 是核心服务接口之一,专门用于处理流程与表单的交互,尤其针对动态表单、普通表单和外置表单这三种表单类型提供了统一的操作入口。其主要作用体现在以下几个方面:

  1. 表单数据的管理与交互
    FormService 承担着表单数据 “获取 - 提交 - 流转” 的全流程管理,是前端表单与后端流程引擎的核心交互枢纽。

获取任务表单数据:
当用户需要办理流程任务时,通过 getTaskFormData(String taskId) 方法可获取当前任务节点对应的表单完整信息,包括字段名称、类型、默认值、是否必填等,直接用于前端页面动态渲染表单。
示例场景:部门经理进入 “采购申请审核” 任务页面时,系统通过该方法拉取审核表单的字段配置,生成包含 “审批结果”“审批意见” 的表单界面。
提交表单数据:
用户填写表单后,通过 submitTaskFormData(String taskId, Map<String, String> properties) 方法将表单数据(以键值对形式)提交给流程引擎。引擎会自动完成两件事:① 将数据存储为流程变量;② 驱动流程从当前任务节点流转到下一个节点。

  1. 支持三种表单类型的统一操作
    FormService 对 Activiti 的三种表单类型提供了标准化处理逻辑,开发者无需为不同表单类型编写差异化交互代码。

动态表单(Dynamic Forms)
表单字段定义在流程 XML 文件中,通过 <formProperty> 标签配置(如 <formProperty id="approvalResult" name="审批结果" type="enum" required="true"/>)。
FormService 可直接解析 XML 中的表单配置,自动生成表单结构,并在提交时校验字段合法性(如必填项、数据类型),最后将数据同步为流程变量。
普通表单(Plain Forms)
表单由开发者自定义页面实现(如 JSP、Vue 页面),流程 XML 中仅通过 formKey 绑定页面标识(如 <userTask id="deptAudit" name="部门审核" formKey="/pages/audit/dept-audit.jsp"/>)。
FormService 的核心作用是 “关联” 与 “转化”:通过 formKey 定位表单页面,提交时将自定义页面的表单数据转化为标准流程变量,确保数据能被流程引擎识别。
外置表单(External Forms)
表单定义在独立的外部文件中(通常为 .form 格式,本质是 XML 结构),如 purchase-audit.form。
FormService 可通过 getStartFormData 或 getTaskFormData 方法加载外部表单文件,解析其中的字段配置,后续数据提交与动态表单逻辑一致,实现 “表单与流程解耦”。

  1. 流程启动与表单的关联
    对于需要 “填写表单后启动流程” 的场景(如职工发起采购申请需先填写申请单),FormService 提供了完整的启动表单处理能力。

获取启动表单数据:
通过 getStartFormData(String processDefinitionId) 方法获取流程启动时所需的表单信息,包括启动节点的表单字段配置,用于渲染 “流程启动表单”。
示例:职工点击 “发起采购申请” 时,系统通过该方法拉取包含 “采购金额”“采购用途”“申请人” 的启动表单配置。
通过表单启动流程:
用户填写启动表单后,通过 submitStartFormData(String processDefinitionId, Map<String, String> properties) 方法可一次性完成 “提交表单数据” 和 “启动流程实例” 两个操作。提交的数据会自动作为流程实例的初始化变量,传递到后续任务节点。

  1. 表单数据与流程变量的自动映射
    这是 FormService 最核心的 “简化开发” 特性:开发者无需手动编写代码将表单数据存入流程变量,FormService 会自动完成映射。

映射逻辑:表单提交时,Map<String, String> 中的键(如 “purchaseAmount”)对应流程变量名,值(如 “5000”)对应变量值。
存储位置:映射后的流程变量会同时存储在两个表中:① ACT_RU_VARIABLE(运行时变量表,流程运行中使用);② ACT_HI_VARINST(历史变量表,流程结束后用于追溯)。
实际价值:流程后续节点可直接使用这些变量(如网关判断 “采购金额> 10000 则需总经理审核”,任务分配 “申请人所在部门的经理为审核人”),无需额外数据查询。

  1. 历史表单数据的追溯
    虽然 FormService 主要处理 “运行时” 表单交互,但它提交的表单数据会以流程变量形式被引擎持久化,结合 HistoryService 可实现完整的表单数据追溯,满足审计需求。

追溯方式:通过 HistoryService.createHistVariableInstanceQuery() 方法,根据流程实例 ID 或任务 ID 查询历史表单数据。
示例代码:
List<HistVariableInstance> varList = historyService.createHistVariableInstanceQuery()

    .processInstanceId(procInstId)
    .variableNames(Arrays.asList("approvalResult", "approvalComment"))
    .list();

// 遍历获取部门经理的审批结果和意见
for (HistVariableInstance var : varList) {

System.out.println(var.getVariableName() + ": " + var.getValue());

}

应用场景:企业审计时,可查询某采购申请流程的所有节点表单数据,追溯 “谁在什么时间提交了什么审批意见”。
核心方法示例(Java 代码)
以下是 FormService 最常用的 4 个核心方法的完整代码示例,可直接复制到项目中使用。
import org.activiti.engine.FormService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.form.StartFormData;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.runtime.ProcessInstance;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FormServiceDemo {

public static void main(String[] args) {
    // 1. 初始化流程引擎
    ProcessEngine processEngine = ProcessEngineConfiguration
            .createStandaloneInMemProcessEngineConfiguration()
            .buildProcessEngine();
    FormService formService = processEngine.getFormService();

    // 流程定义ID(需替换为实际项目中的流程定义ID)
    String processDefinitionId = "purchase-process:1:45004";
    // 任务ID(需替换为实际运行中的任务ID)
    String taskId = "50002";

    // 2. 获取任务表单数据(用于渲染前端表单)
    TaskFormData taskFormData = formService.getTaskFormData(taskId);
    List<FormProperty> formProperties = taskFormData.getFormProperties();
    System.out.println("任务表单字段列表:");
    for (FormProperty prop : formProperties) {
        System.out.printf("字段ID:%s,字段名称:%s,是否必填:%s%n",
                prop.getId(), prop.getName(), prop.isRequired());
    }

    // 3. 提交任务表单数据(驱动流程流转)
    Map<String, String> taskFormDataMap = new HashMap<>();
    taskFormDataMap.put("approvalResult", "agree"); // 审批结果:同意
    taskFormDataMap.put("approvalComment", "采购需求合理,同意申请"); // 审批意见
    formService.submitTaskFormData(taskId, taskFormDataMap);
    System.out.println("任务表单提交成功,流程已流转至下一节点");

    // 4. 获取流程启动表单数据(用于渲染启动表单)
    StartFormData startFormData = formService.getStartFormData(processDefinitionId);
    System.out.println("启动表单字段列表:");
    for (FormProperty prop : startFormData.getFormProperties()) {
        System.out.printf("字段ID:%s,字段名称:%s,默认值:%s%n",
                prop.getId(), prop.getName(), prop.getValue());
    }

    // 5. 提交启动表单并启动流程实例
    Map<String, String> startFormDataMap = new HashMap<>();
    startFormDataMap.put("purchaseAmount", "5000"); // 采购金额
    startFormDataMap.put("purchasePurpose", "办公电脑采购"); // 采购用途
    startFormDataMap.put("applicant", "张三"); // 申请人
    ProcessInstance processInstance = formService.submitStartFormData(processDefinitionId, startFormDataMap);
    System.out.printf("流程实例启动成功,实例ID:%s%n", processInstance.getId());

    // 关闭流程引擎
    processEngine.close();
}

}

总结
FormService 是 Activiti 中连接表单交互与流程引擎的核心桥梁,其价值体现在三个层面:
简化开发:自动完成表单数据与流程变量的映射,无需手动处理数据存储与流转;
统一标准:对三种表单类型提供标准化操作接口,降低多表单类型的维护成本;
支撑业务:通过表单与流程的深度绑定,实现 “表单驱动流程” 的业务模式,同时保障数据可追溯性。
无论是简单的审批流程,还是复杂的多节点业务流程,FormService 都是实现 “流程与表单协同” 的关键组件。