springboot+flowable第二节(流程基本操作)

mysql数据库

1.部署流程

举例:部署一个如下图的流程
在这里插入图片描述

在src/main/resources下创建processes文件夹,然后新建bpmn20.xml文件
在这里插入图片描述

添加如下内容:

<?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:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" 
			xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" 
			xmlns:flowable="http://flowable.org/bpmn" 
			xmlns:di="http://www.omg.org/spec/DD/20100524/DI" 
			xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
			targetNamespace="http://www.flowable.org/processdef">


	<!-- 流程定义信息
	id:在数据库里会存在key_字段中
	name:流程名字
	-->
  <process id="process_fzoauj5k" name="审核流程">

	<!--开始事件:流程的起点
	id:开始节点的ID
	name:开始节点的名称
	outgoing:记录连线的顺序流,outgoing表示从该节点输出的线
	-->
    <startEvent id="startNode1" name="开始">
      <outgoing>Flow_0ksehsm</outgoing>
    </startEvent>
    
	<!--结束事件:流程的终点
	id:结束节点的ID
	name:结束节点的名称
	incoming:记录连线的顺序流,incoming表示输入该节点的线
	-->
    <endEvent id="Event_08rzeth" name="结束">
      <incoming>Flow_18upiqx</incoming>
    </endEvent>
	
	<!--顺序流:执行时会从一个节点流向另一个节点
	id:顺序流的ID
	sourceRef:源头节点ID
	targetRef:目标节点ID
	-->
    <sequenceFlow id="Flow_0ksehsm" sourceRef="startNode1" targetRef="Activity_01fk1po" />
    <sequenceFlow id="Flow_1huwgzm" sourceRef="Activity_01fk1po" targetRef="Activity_0ipmowu" />
    <sequenceFlow id="Flow_18upiqx" sourceRef="Activity_0ipmowu" targetRef="Event_08rzeth" />
	
	
	<!--用户任务:需要指定用户来执行
	flowable:assignee:任务受理人,这里先写为固定,设受理人的用户ID为1
	incoming:记录连线的顺序流,incoming表示输入该节点的线
	outgoing:记录连线的顺序流,outgoing表示从该节点输出的线
	-->
    <userTask id="Activity_01fk1po" name="申请" flowable:assignee="1">
      <incoming>Flow_0ksehsm</incoming>
      <outgoing>Flow_1huwgzm</outgoing>
    </userTask>
	
	<!--用户任务:需要指定用户来执行
	flowable:assignee:任务受理人,这里先写为固定,设受理人的用户ID为2
	-->
    <userTask id="Activity_0ipmowu" name="审核" flowable:assignee="2">
      <incoming>Flow_1huwgzm</incoming>
      <outgoing>Flow_18upiqx</outgoing>
    </userTask>
	
  </process>
  
  
  <!--节点在流程图中的位置,没有前端可不写-->
  <bpmndi:BPMNDiagram id="BPMNDiagram_flow">
    <bpmndi:BPMNPlane id="BPMNPlane_flow" bpmnElement="process_fzoauj5k">
      <bpmndi:BPMNEdge id="Flow_0ksehsm_di" bpmnElement="Flow_0ksehsm">
        <di:waypoint x="-15" y="190" />
        <di:waypoint x="70" y="190" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1huwgzm_di" bpmnElement="Flow_1huwgzm">
        <di:waypoint x="170" y="190" />
        <di:waypoint x="260" y="190" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_18upiqx_di" bpmnElement="Flow_18upiqx">
        <di:waypoint x="360" y="190" />
        <di:waypoint x="452" y="190" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="BPMNShape_startNode1" bpmnElement="startNode1">
        <omgdc:Bounds x="-45" y="175" width="30" height="30" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="-42" y="212" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_08rzeth_di" bpmnElement="Event_08rzeth">
        <omgdc:Bounds x="452" y="172" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="459" y="215" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_19z5ig5_di" bpmnElement="Activity_01fk1po">
        <omgdc:Bounds x="70" y="150" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_09wpg3z_di" bpmnElement="Activity_0ipmowu">
        <omgdc:Bounds x="260" y="150" width="100" height="80" />
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
  
</definitions>

启动springboot,resource/processes/下的bpmn文件将会自动载入,数据会保存在act_re_deployment和act_re_procdef表中。
在这里插入图片描述

act_re_deployment( 部署信息表)

字段字段名称字段默认值数据类型备注
ID_主键varchar
NAME_名称varchar
CATEGORY_分类varchar
TENANT_ID_租户IDvarchar
DEPLOY_TIME_部署时间timestamp

act_re_procdef( 流程定义数据表)

字段字段名称字段默认值数据类型备注
ID_主键varchar
REV_版本号int
CATEGORY_分类varchar
NAME_名称varchar
KEY_标识varchar
VERSION_版本int
DEPLOYMENT_ID_部署IDvarchar
RESOURCE_NAME_资源名称varchar
DGRM_RESOURCE_NAME_图片资源名称varchar
DESCRIPTION_描述varchar
HAS_START_FORM_KEY_表单是否有开始节点的标识tinyintstart节点是否存在formKey
0否 1是
HAS_GRAPHICAL_NOTATION_拥有图形信息tinyint
SUSPENSION_STATE_挂起状态int
暂停状态 1激活 2暂停
TENANT_ID_租户IDvarchar

2.引入流程引擎

在这里插入图片描述

FlowServiceFactory.java

package com.example.demo.factory;

import org.flowable.engine.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.flowable.form.api.FormService;

import javax.annotation.Resource;

/**
 * flowable 引擎注入封装
 */
@Component
public class FlowServiceFactory {
    @Resource
    protected RepositoryService repositoryService;

    @Resource
    protected RuntimeService runtimeService;

    @Resource
    protected IdentityService identityService;

    @Resource
    protected TaskService taskService;

    @Resource
    protected FormService formService;

    @Resource
    protected HistoryService historyService;

    @Resource
    protected ManagementService managementService;

    @Qualifier("processEngine")
    @Resource
    protected ProcessEngine processEngine;

    public RepositoryService getRepositoryService() {
        return repositoryService;
    }

    public RuntimeService getRuntimeService() {
        return runtimeService;
    }

    public IdentityService getIdentityService() {
        return identityService;
    }

    public TaskService getTaskService() {
        return taskService;
    }

    public FormService getFormService() {
        return formService;
    }

    public HistoryService getHistoryService() {
        return historyService;
    }

    public ManagementService getManagementService() {
        return managementService;
    }

    public ProcessEngine getProcessEngine() {
        return processEngine;
    }
}

3.启动流程

上面引入的xml文件相当于定义了一套工作流程,大家都可以使用这个流程。
拿请假流程举例:人员A和B都申请请假,那么就认为A启动了一次流程,B也启动了一次流程。这一套流程就拥有了两个流程实例。

package com.example.demo.controller;

import org.flowable.engine.IdentityService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ProcessController {

    private final RuntimeService runtimeService;

    private final IdentityService identityService;

    public ProcessController(RuntimeService runtimeService, IdentityService identityService) {
        this.runtimeService = runtimeService;
        this.identityService = identityService;
    }


    @PostMapping("/start")
    @Transactional(rollbackFor = Exception.class)
    public String start(@RequestParam String key) {
        try {
            // 设置流程启动用户
            identityService.setAuthenticatedUserId("1");
            //根据key启动(还可以根据ID、TENANT_ID_启动),返回流程实例(正在运行的流程)
            ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key);
            String processInstanceId = processInstance.getProcessInstanceId();
            //返回流程实例ID
            return processInstanceId;
        } catch (Exception e) {
            e.printStackTrace();
            return "启动失败!";
        }
    }

}

使用postman访问接口,其中key为xml中的流程id
在这里插入图片描述
在这里插入图片描述

启动完成之后,返回了流程实例ID,运行中的流程数据会保存到act_ru_actinst、act_ru_execution、act_ru_identitylink、act_ru_task表中

act_ru_actinst:存储运行中各个节点的信息:

act_ru_identitylink: 存储候选用户、处理人相关数据

act_ru_task :存储审批代办相关信息

Flowable包下的常用服务类:
RuntimeService :用于查询运行中的流程实例相关信息。
TaskService:用于查询代办、代签、签收、办理等操作。
HistoryService:用于查询流程相关历史数据。

4.查询待办列表


	@Autowired
    private TaskService taskService;

	/**获取指定用户的待办的任务列表
     * 代办
     * */
    @GetMapping("/getNeedDoTasks")
    @Transactional(rollbackFor = Exception.class)
    public String getNeedDoTasks() {
        //设当前登录用户ID
        String userId = "1";

        //taskCandidateOrAssigned 表示不管是任务的候选人还是直接分配的人都可以查到
        List<Task> tasks = taskService.createTaskQuery()
                .taskCandidateOrAssigned(userId)
                .list();

        if (!tasks.isEmpty()) {
            List<Map<String, Object>> list = new ArrayList<>();
            for (Task task : tasks) {
                Map<String, Object> map = new HashMap<>();
                //代办id
                String taskId = task.getId();
                //代办节点名称
                String taskName = task.getName();
                //创建时间
                Date createTime = task.getCreateTime();
                map.put("taskId", taskId);
                map.put("taskName", taskName);
                map.put("createTime", createTime);
                list.add(map);
            }
            return listToString(list,',');
        }

        return "当前用户在当前流程实例中并无待办!";
    }



// 列表转字符串
    public String listToString(List list, char separator) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            sb.append(list.get(i)).append(separator);
        }
        return sb.toString().substring(0,sb.toString().length()-1);
    }

发起查询
在这里插入图片描述

可以看到用户“1”有一条待办任务,任务ID为71a2deb3-b25b-11ec-9428-d46a6adef6a5
接下来我们去审批这个任务。

5.审批通过

/**审批通过并跳转流程*/
    @GetMapping("/audit")
    @Transactional(rollbackFor = Exception.class)
    public String audit(@RequestParam String taskId) {
        try {
            //跳转流程
            taskService.complete(taskId);
            return "已审批";
        } catch (Exception e) {
            e.printStackTrace();
            return "跳转失败!";
        }
    }

访问接口:
在这里插入图片描述
审批成功后我们再查询一下待办任务列表看看还有没有待办
在这里插入图片描述

可以看到,审批通过后,在用户“1”的待办任务里已经查不到刚才的任务了。
接下来我们去看看用户“1”的已办任务列表。

6.查询已办列表

    @Autowired
    private HistoryService historyService;
    
    /**获取已办任务列表
     * 已办
     * */
    @GetMapping("/getAlreadyDoTasks")
    @Transactional(rollbackFor = Exception.class)
    public String getAlreadyDoTasks() {
        //获取当前登录用户ID
        long userId = 1L;

        List<HistoricTaskInstance> taskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
                .includeProcessVariables()
                .finished()
                .taskAssignee(userId+"")
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .list();

        if (!taskInstanceQuery.isEmpty()) {
            List<Map<String, Object>> list = new ArrayList<>();
            for (HistoricTaskInstance task : taskInstanceQuery) {
                Map<String, Object> map = new HashMap<>();
                //代办id
                String taskId = task.getId();
                //代办节点名称
                String taskName = task.getName();
                //创建时间
                Date createTime = task.getCreateTime();
                map.put("taskId", taskId);
                map.put("taskName", taskName);
                map.put("createTime", createTime);
                list.add(map);
            }
            return listToString(list,',');
        }
        return "暂无已办";
    }

访问接口:
在这里插入图片描述

可以看到刚才的申请任务已经进入到了已办列表。

7.查询发起列表

/**获取我发起的流程列表
     * 发起
     * 流程列表
     * */
    @GetMapping("/getMyStartUpProcesses")
    @Transactional(rollbackFor = Exception.class)
    public String getMyStartUpProcesses() {
        List<HistoricProcessInstance> historicProcessInstanceList=historyService.createHistoricProcessInstanceQuery()
                .startedBy("1")
                .includeProcessVariables()
                .orderByProcessInstanceStartTime()
                .desc()
                .list();
        return listToString(historicProcessInstanceList,',');
    }

访问接口:
在这里插入图片描述

可以看到用户“1”,发起了一个【审核流程】。


完事了,下一节写动态设置审批人。
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悢七

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值