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=还没人认领
相关推荐
Shaoxi Zhang21 小时前
JAVA学习笔记035——对象和JSON格式
java·笔记·学习
Oll Correct21 小时前
Adobe illustrator 案例六:手枪图标绘制
笔记·ui·adobe·illustrator
摇滚侠1 天前
《Docker技术入门与实战 第4版》阅读笔记 2 Docker 镜像
笔记·docker·容器
疯狂打码的少年1 天前
【数据结构】图的遍历:深度优先搜索(DFS)
数据结构·笔记·算法·深度优先
智者知已应修善业1 天前
【51单片机数码管逐位显示1-8余位不亮】2024-10-23
c语言·经验分享·笔记·嵌入式硬件·51单片机
Wang's Blog1 天前
PostgreSQL笔记16: 索引基础——概念、类型、创建与最佳实践
数据库·笔记·postgresql
ysa0510301 天前
c++常用自带函数用法与注意
c++·笔记·算法
Wang's Blog1 天前
PostgreSQL笔记24: Background Writer 后台写进程的原理、参数调优与可观测性演进
数据库·笔记·postgresql
无聊的菜鸟1 天前
TMS320F2806X学习笔记(一)—— 了解片上资源
笔记·ti·c2000·f2806x
优化Henry1 天前
学习笔记之爱立信站点指向证书执行
运维·服务器·网络·笔记·学习·信息与通信