Flowable——表单详解

Flowable表单

Flowable提供了一种简单灵活的方式,用来为业务流程中的人工步骤添加表单。有两种使用表单的方法:

  • 使用(由表单设计器创建的)表单定义的内置表单渲染(弊端是每一步都要设计表单)。
  • 外部表单渲染。使用外部表单渲染时,可以使用表单参数;也可以使用表单key定义,引用外部的、使用自定义的代码解析表单。

1、内置表单

在这里插入图片描述

在这里插入图片描述

<process id="FormProcess" name="FormProcess" isExecutable="true">
  <startEvent id="startEvent1" flowable:formFieldValidation="true">
    <extensionElements>
      <flowable:formProperty id="day" name="请假天数" type="long"></flowable:formProperty>
      <flowable:formProperty id="startTime" name="开始事件" type="string"></flowable:formProperty>
      <flowable:formProperty id="reason" name="请假原因" type="string"></flowable:formProperty>
    </extensionElements>
  </startEvent>
  <userTask id="sid-EF0C904B-5FF2-42FC-87C3-AD42B9834020" name="人事审批" flowable:formFieldValidation="true">
    <extensionElements>
      <flowable:formProperty id="day" name="请假天数" type="long"></flowable:formProperty>
      <flowable:formProperty id="startTime" name="开始事件" type="string"></flowable:formProperty>
      <flowable:formProperty id="reason" name="请假原因" type="string"></flowable:formProperty>
    </extensionElements>
  </userTask>
  <sequenceFlow id="sid-9A896AC0-C14C-4493-A64B-496EBCEC8E03" sourceRef="startEvent1" targetRef="sid-EF0C904B-5FF2-42FC-87C3-AD42B9834020"></sequenceFlow>
  <endEvent id="sid-18092534-128B-4889-94D5-CAC07A70B480"></endEvent>
  <sequenceFlow id="sid-9A69EA2E-A2D6-4818-B9F4-770D60FF8070" sourceRef="sid-EF0C904B-5FF2-42FC-87C3-AD42B9834020" targetRef="sid-18092534-128B-4889-94D5-CAC07A70B480"></sequenceFlow>
</process>

1.1、启动流程实例

@RunWith(SpringRunner.class)
@SpringBootTest
public class AppApplicationTest {


    @Autowired
    RepositoryService repositoryService;

    @Autowired
    FormService formService;

    /**
     * 启动流程
     */
    @Test
    public void startFormFlow() {
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("FormProcess")
                .singleResult();
        Map<String,String> map = new HashMap<>();
        map.put("day","1");
        map.put("startTime","2023-01-29 21:03");
        map.put("reason","去看电影《深海》");
        ProcessInstance processInstance = formService.submitStartFormData(pd.getId(), map);
        System.out.println("processInstance.getProcessInstanceId() = " + processInstance.getProcessInstanceId());
    }
}
processInstance.getProcessInstanceId() = 4967f4a8-56ab-11ee-948a-f6ef923dabbb

1.2、获取表单字段

/**
 * 获取表单字段
 */
@Test
public void getStartFormData() {
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("FormProcess")
            .singleResult();
    StartFormData startFormData = formService.getStartFormData(pd.getId());
    List<FormProperty> formProperties = startFormData.getFormProperties();
    for (FormProperty formProperty : formProperties) {
        String id = formProperty.getId();
        String name = formProperty.getName();
        FormType type = formProperty.getType();
        System.out.println("id = " + id);
        System.out.println("name = " + name);
        System.out.println("type.getClass() = " + type.getClass());
    }
}
id = day
name = 请假天数
type.getClass() = class org.flowable.engine.impl.form.LongFormType
id = startTime
name = 开始事件
type.getClass() = class org.flowable.engine.impl.form.StringFormType
id = reason
name = 请假原因
type.getClass() = class org.flowable.engine.impl.form.StringFormType

1.3、表单信息修改与保存

/**
 * 保存表单,并查询表单
 */
@Test
public void saveAndQueryFormData() {
    Task task = taskService.createTaskQuery()
            .processDefinitionKey("FormProcess")
            .singleResult();
    System.out.println("————————————————————第一次查询————————————————————");
    TaskFormData taskFormData = formService.getTaskFormData(task.getId());
    List<FormProperty> formProperties = taskFormData.getFormProperties();
    for (FormProperty formProperty : formProperties) {
        System.out.println("formProperty.getId() = " + formProperty.getId());
        System.out.println("formProperty.getName() = " + formProperty.getName());
        System.out.println("formProperty.getValue() = " + formProperty.getValue());
    }
    System.out.println("————————————————————修改保存————————————————————");
    Map<String, String> map = new HashMap<>();
    map.put("day", "3");
    map.put("startTime", "2023-01-27 22:42");
    map.put("reason", "测试以下提交流程");
    formService.saveFormData(task.getId(), map);
    System.out.println("————————————————————第二次查询————————————————————");
    TaskFormData taskFormData2 = formService.getTaskFormData(task.getId());
    List<FormProperty> formProperties2 = taskFormData2.getFormProperties();
    for (FormProperty formProperty2 : formProperties2) {
        System.out.println("formProperty.getId() = " + formProperty2.getId());
        System.out.println("formProperty.getName() = " + formProperty2.getName());
        System.out.println("formProperty.getValue() = " + formProperty2.getValue());
    }
}
————————————————————第一次查询————————————————————
formProperty.getId() = day
formProperty.getName() = 请假天数
formProperty.getValue() = 1
formProperty.getId() = startTime
formProperty.getName() = 开始事件
formProperty.getValue() = 2023-01-29 21:03
formProperty.getId() = reason
formProperty.getName() = 请假原因
formProperty.getValue() = 去看电影《深海》
————————————————————修改保存————————————————————
————————————————————第二次查询————————————————————
formProperty.getId() = day
formProperty.getName() = 请假天数
formProperty.getValue() = 3
formProperty.getId() = startTime
formProperty.getName() = 开始事件
formProperty.getValue() = 2023-01-27 22:42
formProperty.getId() = reason
formProperty.getName() = 请假原因
formProperty.getValue() = 测试以下提交流程

1.4、完成任务

/**
 * 完成任务
 */
@Test
public void completeTask() {
    Task task = taskService.createTaskQuery()
            .processDefinitionKey("FormProcess")
            .singleResult();
    System.out.println(task.getAssignee() + "-完成任务-" + task.getId());
    Map<String, String> map = new HashMap<>();
    map.put("day", "4");
    map.put("startTime", "2023-01-30 22:42");
    map.put("reason", "一起去看《深海》吧");
    formService.submitTaskFormData(task.getId(), map);
}
null-完成任务-2638fbf1-56b2-11ee-9b6e-f6ef923dabbb

1.5、总结内置表单

使用方法:

StartFormData FormService.getStartFormData(String processDefinitionId)

TaskFormData FormService.getTaskFormData(String taskId)

2、外置表单

2.1、json表单

2.1.1、配置表单位置和表单后缀名

集成SpringBoot的Flowable提供了.form的自动部署机制。会对保存在forms文件夹下的表单自动部署。

flowable:
  # 关闭异步,不关闭历史数据的插入就是异步的,会在同一个事物里面,无法回滚
  # 开发可开启会提高些效率,上线需要关闭
  async-executor-activate: true
  #  将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
  database-schema-update: true
  form:
    resource-suffixes: "**.form"    # 默认的表单⽂件后缀
    resource-location: "classpath*:/forms/"    # 默认的表单⽂件位置
2.1.2、创建form表单
{
    "key": "qjlc.form",
    "name": "经理审批表单",
    "fields": [
        {
            "id": "days",
            "name": "请假天数",
            "type": "string",
            "required": true,
            "placeholder": "empty"
        },
        {
            "id": "reason",
            "name": "请假原因",
            "type": "string",
            "required": true,
            "placeholder": "empty"
        },
        {
            "id": "startTime",
            "name": "开始时间",
            "type": "date",
            "required": true,
            "placeholder": "empty"
        }
    ]
}

在这里插入图片描述

在这里插入图片描述

<process id="JsonFormProcess" name="JsonFormProcess" isExecutable="true">
  <startEvent id="startEvent1" flowable:formKey="qjlc.form" flowable:formFieldValidation="true"></startEvent>
  <userTask id="sid-AC4965BC-5EE4-4C7E-B01F-3286DAEA560E" name="经理审批表单" flowable:formKey="qjlc.form" flowable:formFieldValidation="true"></userTask>
  <sequenceFlow id="sid-73E4B9A5-11B1-4C60-B6B5-F4FB28648452" sourceRef="startEvent1" targetRef="sid-AC4965BC-5EE4-4C7E-B01F-3286DAEA560E"></sequenceFlow>
  <endEvent id="sid-724562C1-FFD5-4333-A97C-1A87196562A8"></endEvent>
  <sequenceFlow id="sid-D1F0DB91-3566-4599-B228-61F7BD2875E6" sourceRef="sid-AC4965BC-5EE4-4C7E-B01F-3286DAEA560E" targetRef="sid-724562C1-FFD5-4333-A97C-1A87196562A8"></sequenceFlow>
</process>
2.1.3、测试案例

启动流程

/**
 * 启动JSNOForm流程
 */
@Test
public void startJsonFormFlow() {
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("JsonFormProcess")
            .singleResult();
    Map<String,Object> map = new HashMap<>();
    map.put("days","2");
    map.put("startTime",new Date());
    map.put("reason","世界那么大,我想去看看");
    ProcessInstance pi = runtimeService.startProcessInstanceWithForm(pd.getId(), "请假开始", map, pd.getName());
    System.out.println("processInstance.getId() = " + pi.getId());
}
processInstance.getId() = 3b87fc28-56b9-11ee-9d83-f6ef923dabbb

在这里插入图片描述

获取表单信息

/**
 * 获取JSON表单信息
 */
@Test
public void getJsonFormFields() {
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("JsonFormProcess")
            .singleResult();
    Task task = taskService.createTaskQuery()
            .processDefinitionId(pd.getId())
            .singleResult();
    FormInfo formInfo = taskService.getTaskFormModel(task.getId());
    System.out.println("formInfo.getId() = " + formInfo.getId());
    SimpleFormModel formModel = (SimpleFormModel) formInfo.getFormModel();
    List<FormField> fields = formModel.getFields();
    fields.forEach(e -> {
        System.out.println("===================================");
        System.out.println("e.getId() = " + e.getId());
        System.out.println("e.getName() = " + e.getName());
        System.out.println("e.getType() = " + e.getType());
        System.out.println("e.getValue() = " + e.getValue());
    });
}
formInfo.getId() = b3064dda-56b8-11ee-9e24-f6ef923dabbb
===================================
e.getId() = days
e.getName() = 请假天数
e.getType() = string
e.getValue() = 2
===================================
e.getId() = reason
e.getName() = 请假原因
e.getType() = string
e.getValue() = 世界那么大,我想去看看
===================================
e.getId() = startTime
e.getName() = 开始时间
e.getType() = date
e.getValue() = 2023-9-19

完成任务

/**
 * 完成JSON表单任务
 */
@Test
public void completeJsonFormTask() {
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("JsonFormProcess")
            .singleResult();
    Task task = taskService.createTaskQuery()
            .processDefinitionId(pd.getId())
            .singleResult();
    FormInfo formInfo = taskService.getTaskFormModel(task.getId());
    Map<String,Object> map = new HashMap<>();
    map.put("days","1");//只批准1天假期
    map.put("startTime",new Date());
    map.put("reason","世界那么大,我想去看看");
    taskService.completeTaskWithForm(task.getId(), formInfo.getId(), "批准请假", map);
    System.out.println("完成任务:" + task.getId());
}
完成任务:3b8cb723-56b9-11ee-9d83-f6ef923dabbb

查询历史表单信息

/**
 * 查询历史表单信息
 */
@Test
public void getHistoryFormFields() {
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("JsonFormProcess")
            .singleResult();
    HistoricTaskInstance instance = historyService.createHistoricTaskInstanceQuery()
            .processDefinitionId(pd.getId())
            .singleResult();
    FormInfo info = taskService.getTaskFormModel(instance.getId());
    FormModel model = info.getFormModel();
    if (model != null) {
        List<FormField> fields = ((SimpleFormModel) model).getFields();
        for (FormField field : fields) {
            System.out.println(field.getName() + " : " + field.getValue());
        }
    }
}
请假天数 : 1
请假原因 : 世界那么大,我想去看看
开始时间 : 19-9-2023

2.2、Html表单

2.2.1、绘制流程

在这里插入图片描述

<process id="HtmlFormProcess" name="HtmlFormProcess" isExecutable="true">
  <startEvent id="startEvent1" flowable:formKey="qjlc.html" flowable:formFieldValidation="true"></startEvent>
  <userTask id="sid-38161C41-7FA6-4A12-BCDE-DE203A99406F" name="经理审批" flowable:formKey="approval.html" flowable:formFieldValidation="true"></userTask>
  <sequenceFlow id="sid-65555240-A310-4394-A483-37C00B621EEC" sourceRef="startEvent1" targetRef="sid-38161C41-7FA6-4A12-BCDE-DE203A99406F"></sequenceFlow>
  <endEvent id="sid-8B13C30E-2839-4356-BB8E-D534AD470E91"></endEvent>
  <sequenceFlow id="sid-45F117C6-6FE4-43B1-8056-290C2A72F71F" sourceRef="sid-38161C41-7FA6-4A12-BCDE-DE203A99406F" targetRef="sid-8B13C30E-2839-4356-BB8E-D534AD470E91"></sequenceFlow>
</process>
2.2.2、创建Html表单

qjlc.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="">
    <table>
        <tr>
            <td>请假天数:</td>
            <td><input type="text" name="days"></td>
        </tr>
        <tr>
            <td>请假理由:</td>
            <td><input type="text" name="reason"></td>
        </tr>
        <tr>
            <td>起始时间:</td>
            <td><input type="date" name="startTime"></td>
        </tr>
        <tr>
            <td><input type="submit" value="提交"></td>
        </tr>
    </table>
</form>
</body>
</html>

approval.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="">
    <table>
        <tr>
            <td>请假天数:</td>
            <td><input type="text" name="days" value="${days}"></td>
        </tr>
        <tr>
            <td>请假理由:</td>
            <td><input type="text" name="reason" value="${reason}"></td>
        </tr>
        <tr>
            <td>起始时间:</td>
            <td><input type="date" name="startTime" value="${startTime}"></td>
        </tr>
        <tr>
            <td><input type="submit" value="提交"></td>
        </tr>
    </table>
</form>
</body>
</html>
2.2.3、测试案例

部署表单

/**
 * 部署Html表单
 */
/**
 * 部署Html表单
 */
@Test
public void deployHtmlForm() {
    DeploymentBuilder builder = repositoryService.createDeployment();
    //外置表单的部署需要和流程图一起部署,只有一起部署,他们才会有相同的 DEPLOYMENT_ID,
    //否则两者的 DEPLOYMENT_ID 不同,在后续的查找中就找不到对应的表单。
    //所以我们选择将所有资源方放在resources/templaets下,手动一起部署
    builder.addClasspathResource("templates/HtmlFormProcess.bpmn20.xml");
    //另外,外置表单的name要和流程定义中的formkey一致
    InputStream is = this.getClass().getClassLoader().getResourceAsStream("templates/qjlc.html");
    builder.addInputStream("qjlc.html", is);
    is = this.getClass().getClassLoader().getResourceAsStream("templates/approval.html");
    builder.addInputStream("approval.html", is);
    Deployment deploy = builder.deploy();
    System.out.println("deployment.getId() = " + deploy.getId());
}
deployment.getId() = b1434682-56cb-11ee-b7b4-f6ef923dabbb

获取启动事件表单信息

/**
 * 获取启动表单信息
 */
@Test
public void getStartHtmlFormContent(){
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
            .latestVersion().processDefinitionKey("HtmlFormProcess").singleResult();
    System.out.println("pd = " + pd);
    String startFormKey = formService.getStartFormKey(pd.getId());
    System.out.println("startFormKey = " + startFormKey);
    String renderedStartForm = (String) formService.getRenderedStartForm(pd.getId());
    System.out.println("renderedStartForm = " + renderedStartForm);
}
pd = ProcessDefinitionEntity[HtmlFormProcess:1:b14b83e7-56cb-11ee-b7b4-f6ef923dabbb]
startFormKey = qjlc.html
renderedStartForm = <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="">
    <table>
        <tr>
            <td>请假天数:</td>
            <td><input type="text" name="days"></td>
        </tr>
        <tr>
            <td>请假理由:</td>
            <td><input type="text" name="reason"></td>
        </tr>
        <tr>
            <td>起始时间:</td>
            <td><input type="date" name="startTime"></td>
        </tr>
        <tr>
            <td><input type="submit" value="提交"></td>
        </tr>
    </table>
</form>
</body>
</html>

启动流程

/**
 * 启动Html表单流程
 */
/**
 * 启动Html表单流程
 */
@Test
public void startHtmlFormFlow() {
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("HtmlFormProcess")
            .singleResult();
    Map<String, String> vars = new HashMap<>();
    vars.put("days", "3");
    vars.put("reason", "去看《深海》");
    vars.put("startTime", new Date().toString());
    ProcessInstance pi = formService.submitStartFormData(pd.getId(), vars);
    System.out.println("pi.getId() = " + pi.getId());
}
pi.getId() = 0de19a57-56cc-11ee-b45d-f6ef923dabbb

获取渲染后的任务表单信息

/**
 * 获取渲染后的任务表单信息
 */
@Test
public void getTaskHtmlFormContent() {
    Task task = taskService.createTaskQuery().processDefinitionKey("HtmlFormProcess").singleResult();
    String renderedForm = (String) formService.getRenderedTaskForm(task.getId());
    System.out.println(renderedForm);
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="">
    <table>
        <tr>
            <td>请假天数:</td>
            <td><input type="text" name="days" value="3"></td>
        </tr>
        <tr>
            <td>请假理由:</td>
            <td><input type="text" name="reason" value="去看《深海》"></td>
        </tr>
        <tr>
            <td>起始时间:</td>
            <td><input type="date" name="startTime" value="Tue Sep 19 17:08:10 CST 2023"></td>
        </tr>
        <tr>
            <td><input type="submit" value="提交"></td>
        </tr>
    </table>
</form>
</body>
</html>

完成任务

/**
 * 完成任务
 */
@Test
public void completeHtmlFormTask() {
    ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("HtmlFormProcess")
            .singleResult();
    Task task = taskService.createTaskQuery()
            .processDefinitionId(pd.getId())
            .singleResult();
    Map<String, String> vars = new HashMap<>();
    vars.put("days", "2");
    vars.put("reason", "去看《深海》吧");
    vars.put("startTime", new Date().toString());
    formService.submitTaskFormData(task.getId(), vars);
}

查询历史表单参数

/**
 * 查询历史表单信息
 */
@Test
public void getHistoryHtmlFormFields() {
    HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()
            .processDefinitionKey("HtmlFormProcess")
            .singleResult();
    List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery()
            .processInstanceId(hpi.getId()).list();
    for (HistoricVariableInstance instance : list) {
        System.out.println(instance.getVariableName() + " " + instance.getValue());
    }
}
reason 去看《深海》吧
days 2
startTime Tue Sep 19 17:12:21 CST 2023

2.3、总结外置表单

2.3.1、获取及提交表单参数

实际上,渲染表单所需的所有数据都组装在下面两个方法:

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)
2.3.2、获取及提交表单数据

获取指定流程实例的表单数据的方法:

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);

表单数据实际存放在流程变量表,所以,用流程变量的方法同样可以获取及提交表单数据。

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Flowable 提供了许多适用于业务流程建模和执行的表单组件,但是有时候我们需要使用自定义表单来满足特定的业务需求。下面是使用 Flowable 自定义表单的一些步骤: 1. 创建表单文件 可以使用 HTML、JavaScript、CSS 等技术来创建表单文件。常见的方式是使用 HTML 和 JavaScript 来创建表单。可以在表单中添加各种输入框、下拉框、复选框等组件。 2. 将表单文件上传至 Flowable 打开 Flowable表单设计器,在设计器的左侧菜单栏中选择“表单”选项卡,然后点击“新建表单”按钮。在弹出的对话框中,选择“上传表单文件”选项,然后选择刚才创建的表单文件并上传。 3. 创建表单模板 在表单设计器中,点击“新建表单模板”按钮。在弹出的对话框中,选择刚才上传的表单文件并设置表单模板的名称和描述。然后,可以在表单设计器中对表单模板进行设置和编辑,例如添加表单字段、设置表单显示样式等。 4. 使用表单模板 创建业务流程时,在流程定义中选择刚才创建的表单模板作为表单。在流程实例执行时,用户可以根据表单模板填写表单数据,并提交表单。 以上是使用 Flowable 自定义表单的基本步骤。需要注意的是,在创建表单文件时,需要考虑表单组件的命名、数据类型等问题,以便在后续的流程定义和执行中正确地处理表单数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值