Flowable流程开发笔记

Flowable 流程引擎开发笔记

常用表

运行时表(流程运行中才有数据,结束后自动清理)

表名 存什么 说明
ACT_RU_TASK 当前待办任务 ASSIGNEE_ 为 null 表示在候选人池,有值表示已被认领
ACT_RU_IDENTITYLINK 任务的候选人/参与者 TYPE_ = candidate 是候选人,assignee 是指派人
ACT_RU_VARIABLE 流程变量 存流程实例级别的变量数据
ACT_RU_EXECUTION 流程执行实例 一个流程实例可能有多条执行线(会签时)
ACT_RU_ACTINST 当前活跃的活动节点 当前流程走到哪个节点了

历史表(流程结束后数据移到这些表)

表名 存什么 说明
ACT_HI_TASKINST 所有任务(含已完成的) 流程的所有审批记录都在这里
ACT_HI_PROCINST 所有流程实例 START_USER_ID_ 是发起人
ACT_HI_ACTINST 所有活动节点历史 每个节点的开始、结束时间
ACT_HI_VARINST 历史流程变量 流程变量变更记录

其他

表名 存什么 说明
ACT_RE_PROCDEF 流程定义 部署的 BPMN 模型
ACT_RE_DEPLOYMENT 部署记录 每次发布流程的版本

常用查询

找当前待办

sql 复制代码
-- 查某人的待办
SELECT * FROM ACT_RU_TASK WHERE ASSIGNEE_ = 'loginName';

-- 查候选人池里的任务
SELECT * FROM ACT_RU_TASK WHERE ASSIGNEE_ IS NULL;

查候选人

sql 复制代码
-- 查某个 task 的所有候选人
SELECT * FROM ACT_RU_IDENTITYLINK 
WHERE TASK_ID_ = 'taskId' AND TYPE_ = 'candidate';

-- 查 group 下的候选人
SELECT * FROM ACT_RU_IDENTITYLINK 
WHERE GROUP_ID_ = 'groupId' AND TYPE_ = 'candidate';

查流程历史

sql 复制代码
-- 查某个流程实例的所有审批记录
SELECT * FROM ACT_HI_TASKINST 
WHERE PROC_INST_ID_ = '流程实例ID' 
ORDER BY START_TIME_;

-- 查某人发起的所有流程
SELECT * FROM ACT_HI_PROCINST WHERE START_USER_ID_ = 'loginName';

TaskTransferService

java 复制代码
package com.oda.apps.iplm.service.impl;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
public class TaskTransferService {

    @Autowired
    private TaskService taskService;

    /**
     * 直接转办给新人(适用于已签收/认领的任务)
     */
    @Transactional(rollbackFor = Exception.class)
    public void reassign(String taskId, String newAssignee) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) throw new RuntimeException("任务不存在:" + taskId);

        taskService.setAssignee(taskId, newAssignee);
        taskService.addComment(taskId, task.getProcessInstanceId(),
                "转办:" + task.getAssignee() + " → " + newAssignee);
        log.info("转办 {}/{} : {} → {}", taskId, task.getName(), task.getAssignee(), newAssignee);
    }

    /**
     * 替换候选人池:移除旧人,加入新人
     * 适用场景:任务没人认领,离职的人从候选人池移除,新人加进去
     */
    @Transactional(rollbackFor = Exception.class)
    public void replaceCandidate(String taskId, String oldUser, String newUser) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) throw new RuntimeException("任务不存在:" + taskId);

        // 如果旧人已经签收了,一并转交
        if (StrUtil.isNotBlank(task.getAssignee()) && task.getAssignee().equals(oldUser)) {
            taskService.setAssignee(taskId, newUser);
        }

        taskService.deleteCandidateUser(taskId, oldUser);
        taskService.addCandidateUser(taskId, newUser);
        taskService.addComment(taskId, task.getProcessInstanceId(),
                "候选人变更:" + oldUser + " → " + newUser);
        log.info("候选人变更 {}/{} : {} → {}", taskId, task.getName(), oldUser, newUser);
    }

    /**
     * 通过流程实例ID转办
     */
    @Transactional(rollbackFor = Exception.class)
    public void transferByProcessInstance(String processInstanceId, String oldUser, String newUser) {
        List<Task> tasks = taskService.createTaskQuery()
                .processInstanceId(processInstanceId)
                .active()
                .list();

        for (Task task : tasks) {
            if (StrUtil.isNotBlank(task.getAssignee()) && task.getAssignee().equals(oldUser)) {
                taskService.setAssignee(task.getId(), newUser);
            }
            taskService.deleteCandidateUser(task.getId(), oldUser);
            taskService.addCandidateUser(task.getId(), newUser);
        }
        log.info("流程 {} 转办:{} → {}", processInstanceId, oldUser, newUser);
    }
}

调用方式

java 复制代码
@Autowired
private TaskTransferService taskTransferService;

// 场景一:任务已被离职的人签收,直接转给新人
taskTransferService.reassign(taskId, "新人LoginName");

// 场景二:任务还在候选人池,替换候选人
taskTransferService.replaceCandidate(taskId, "离职人LoginName", "新人LoginName");

// 场景三:只有流程实例ID,不知道taskId
taskTransferService.transferByProcessInstance(processInstanceId, "离职人LoginName", "新人LoginName");

几个概念

概念 说明
taskId 任务ID,具体某个审批节点的ID,ACT_RU_TASK.ID_
processInstanceId 流程实例ID,整条审批的ID,createWorkflow 的返回值
assignee 指派人,任务被谁签收了,不为 null 表示有人认领了
candidate 候选人,任务可以被这些人处理,谁先点谁签收
claim 签收/认领,候选人把任务拿到自己名下,之后只有他能处理
签收 vs 未签收 assignee 有值=签收了,null=还没人认领
相关推荐
-SOLO-4 小时前
开发笔记-摸鱼输入法
笔记
疯狂打码的少年7 小时前
【计算机网络】TCP/IP协议族(四层体系结构,与OSI对比)
网络·笔记·tcp/ip·计算机网络
xqqxqxxq7 小时前
AI Agent学习:Agent协作工具技术笔记(李博杰《深入理解 AI Agent》4.6观后总结)
笔记·学习
彧azz9 小时前
数据结构:关于图的学习
c语言·数据结构·笔记·学习·算法
自小吃多9 小时前
高云 FPGA 添加时序约束笔记
笔记·fpga开发
彧azz10 小时前
二叉搜索树学习记录
c语言·数据结构·笔记·算法
蒸蒸yyyyzwd10 小时前
机试和Redis学习笔记
c++·笔记·面试
果壳science11 小时前
《自然本源》如何实现狭义相对论的代数化
笔记·算法·几何学
1314lay_100711 小时前
C#调用Sql Server存储过程,并且使用传入表结构
数据库·经验分享·笔记·sqlserver·c#
志尊宝12 小时前
Vue3 零基础每日笔记(015):条件渲染 v-if 与 v-show——控制 DOM 生死还是控制显隐
前端·vue.js·笔记