Flowable & 动态表单(外置表单)

10,968 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

FormService

   Flowable提供了一种简便灵活的方式,用来为业务流程中的人工步骤添加表单。 有两种使用表单的方法:使用(由表单设计器创建的)表单定义的内置表单渲染,以及外部表单渲染。 使用外部表单渲染时,可以使用(自Explorer web应用V5版本支持的)表单参数;也可以使用表单key定义,引用外部的、使用自定义代码解析的表单。可以使用Flowable表单设计器创建表单定义。表单设计器是Flowable Modeler web应用的一部分。也可以直接使用JSON编辑器创建表单定义。 表单引擎用户手册中介绍了表单定义JSON的完整结构。表单支持下列表单字段类型:

  • Text: 渲染为文本框
  • Multiline text: 渲染为多行文本框
  • Number: 渲染为只允许数字值的文本框
  • CheckBox: 渲染为复选框
  • Date: 渲染为日期框
  • Dropdown: 渲染为下拉选择框,候选值由字段定义配置
  • Radio buttons: 渲染为单选按钮,候选值由字段定义配置
  • People: 渲染为选人框,可以选择用户身份表中的用户
  • Group of people: 渲染为选组框,可以选择组身份表中的组
  • Upload: 渲染为上传框
  • Expression: 渲染为一个标签,可以在标签文字中使用JUEL表达式,以使用变量及/或其他动态值

首先准备一个 流程文件和 表单文件

请假流程文件

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
  <process id="leave_key" name="小龙猫请假流程" isExecutable="true">
    <documentation>请假测试</documentation>
    <startEvent id="startEvent1"  flowable:formFieldValidation="true" flowable:formKey="form1"></startEvent>
    <userTask id="sid-97A57F70-08DC-444E-BC1E-0BECB6E2ABFA"  name="员工请假" flowable:assignee="zhangsan" flowable:formFieldValidation="true" flowable:formKey="form1">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-765D3642-F5E0-41FA-AA06-7DF038FD31E1" sourceRef="startEvent1" targetRef="sid-97A57F70-08DC-444E-BC1E-0BECB6E2ABFA"></sequenceFlow>
    <userTask id="sid-0A047298-8229-4DF7-AE2A-47AFFF84B975" name="经理审批" flowable:assignee="lisi" flowable:formFieldValidation="true"  flowable:formKey="form1">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-81DBBA63-898A-4176-9426-B34FC271D20C" sourceRef="sid-97A57F70-08DC-444E-BC1E-0BECB6E2ABFA" targetRef="sid-0A047298-8229-4DF7-AE2A-47AFFF84B975"></sequenceFlow>
    <endEvent id="sid-FF2340BF-AA6A-4FEC-A670-08298BC1A9B7"></endEvent>
    <sequenceFlow id="sid-56709B2A-5C9B-4995-8CC6-96070D0A8F5B" sourceRef="sid-0A047298-8229-4DF7-AE2A-47AFFF84B975" targetRef="sid-FF2340BF-AA6A-4FEC-A670-08298BC1A9B7"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_leave_key">
    <bpmndi:BPMNPlane bpmnElement="leave_key" id="BPMNPlane_leave_key">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-97A57F70-08DC-444E-BC1E-0BECB6E2ABFA" id="BPMNShape_sid-97A57F70-08DC-444E-BC1E-0BECB6E2ABFA">
        <omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-0A047298-8229-4DF7-AE2A-47AFFF84B975" id="BPMNShape_sid-0A047298-8229-4DF7-AE2A-47AFFF84B975">
        <omgdc:Bounds height="80.0" width="100.0" x="320.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-FF2340BF-AA6A-4FEC-A670-08298BC1A9B7" id="BPMNShape_sid-FF2340BF-AA6A-4FEC-A670-08298BC1A9B7">
        <omgdc:Bounds height="28.0" width="28.0" x="465.0" y="164.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-765D3642-F5E0-41FA-AA06-7DF038FD31E1" id="BPMNEdge_sid-765D3642-F5E0-41FA-AA06-7DF038FD31E1">
        <omgdi:waypoint x="129.9499984899576" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="174.9999999999917" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-81DBBA63-898A-4176-9426-B34FC271D20C" id="BPMNEdge_sid-81DBBA63-898A-4176-9426-B34FC271D20C">
        <omgdi:waypoint x="274.9499999999907" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="319.9999999999807" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-56709B2A-5C9B-4995-8CC6-96070D0A8F5B" id="BPMNEdge_sid-56709B2A-5C9B-4995-8CC6-96070D0A8F5B">
        <omgdi:waypoint x="419.95000000000005" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="465.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

表单文件

{
"key":"form1",
"name":"OA请假表单",
"fields":[
{
"id":"days",
"name":"请假天数",
"type":"string",
"required":true,
"placeholder":"empty"
},
{"id":"reason",
"name":"原因",
"type":"string",
"required":true,
"placeholder":"empty"}
]
}

把这个json文件准备好放在 .form文件中(在ide中与Swing会有影响不能编辑所以在编辑器中处理好) 例如:

image.png

下面我们还是先部署下流程

@Test
public void DeployProcess(){
    Deployment holiday = repositoryService.createDeployment()
            .addClasspathResource("小龙猫请假流程.bpmn20.xml")
            .name("小龙猫请假流程")
            .deploy();
}

部署表单

@Autowired
private FormRepositoryService formRepositoryService;
@Autowired
private RepositoryService repositoryService;
@Test
public void  DeployForm(){
    Deployment deployment = repositoryService.createDeploymentQuery().deploymentName("小龙猫请假流程").singleResult();
    formRepositoryService.createDeployment()
            .addClasspathResource("OA请假.form")
            .name("外置表单")
            .parentDeploymentId(deployment.getId())
            .deploy();
}

可以在 DB 这几张表中可以看到我们部署的表单信息

image.png

启动一下 流程

@Test
public void StatrProcess(){
    ProcessDefinition leave_key = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave_key").singleResult();
    Map<String,Object> map=new HashMap<>();
    map.put("days","4");
    map.put("reason","我要去打怪兽维护世界和平");
    runtimeService.startProcessInstanceWithForm(leave_key.getId(),
            "请假",map,
            "OA请假表单");
}

ACT_RU_TASK表中查看 image.png

获取任务表单数据

@Test
public void getTaskFormData(){
//71e05286-df35-11ec-abb7-666ee0fc370d 这个参数是 ACT_RU_TASK的ID_
    FormInfo taskFormModel = taskService.getTaskFormModel("71e05286-df35-11ec-abb7-666ee0fc370d");
    SimpleFormModel formModel = (SimpleFormModel) taskFormModel.getFormModel();
    List<FormField> fields = formModel.getFields();
    fields.forEach(e->{
        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());

    });
}

image.png

我们完成下任务

@Test
public void comleteProcess(){
    Map<String,Object> map=new HashMap<>();
    map.put("days","6");
    map.put("reason","我要去旅游了");
    taskService.completeTaskWithForm("a8c61c99-df31-11ec-84ea-666ee0fc370d","618f9738-df2f-11ec-b007-666ee0fc370d","xx",map);
}

completeTaskWithForm方法的入参是:
ACT_RU_TASK :ID_
ACT_FO_FORM_DEFINITION :ID_
表单参数 : variables

public void completeTaskWithForm(String taskId, String formDefinitionId, String outcome, Map<String, Object> variables) ;

可以看到流程 已经流转到了 经理审批 image.png

再获取下表单数据

@Test
public void getTaskFormData(){
// 经理审批的任务表单数据
    FormInfo taskFormModel = taskService.getTaskFormModel("b07ea376-df36-11ec-944f-666ee0fc370d");
    SimpleFormModel formModel = (SimpleFormModel) taskFormModel.getFormModel();
    List<FormField> fields = formModel.getFields();
    fields.forEach(e->{
        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());

    });
}

image.png

外置表单可以用一些 表单设计器 。注意:一般挂载的时候需要先去部署表单 明天见😁😁😁😁