当前位置: 首页 > news >正文

# 不改流程定义,外挂独立流程,政务会签在任何节点都能做

不改流程定义,外挂独立流程,政务会签在任何节点都能做

--- 非科班野生程序员,深耕政务信息化20年,这套自研Java Web框架支撑过省级新农保、全国首例跨省医保结算等核心民生系统,18年稳定运行至今。这篇复盘在 Activiti 5.13 时代实现政务会签的设计思路,全是政务场景踩坑后的实用解法,不求优雅但求落地。最后感谢豆包、智谱、OpenCode,决策是我做的,代码是我搓的,文字是他们总结的。

背景

Activiti 5.13 的multiInstance(多实例)可以做到并行审批。但它有几个问题:

1. 必须修改流程定义

要在 BPMN 里加一个multiInstance节点,这意味着要改流程定义。政务系统的流程经常变化,每次加一个会签环节都要改一次 BPMN,部署一次.而且会签的参与部门经常变。

2. multiInstance 的参与者是写死的

Activiti 的多实例参与者在流程定义时就写死了。运行时不能动态改变。政务场景下,会签部门经常变,今天三个部门会签,明天换成了四个部门,就得改流程定义重新部署。

3. 会签规则不灵活

政务会签有"一票否决"(任何一个人不通过就整件事打回)、"全部通过"等不同规则,Activiti 的 multiInstance 只支持部分场景,不够灵活.

我的做法是:不用 Activiti 的 multiInstance,不修改主流程定义,而是用独立的子流程 + 自建关联表来实现会签。

--- ## 核心思路

主流程( hq 关联表
┌──────────────┐ ┌───────────────┐ ┌────────────┐
│ 科长审批 │ │ hq 表 │ 会签子流程(独立)
│ 处长审批 │ │ 财务科 │ 财务科 │
│ 处长审批 │──→ pre_proc_inst_id ←──→│ 人事科 │
│ 局长审批 │──→ pre_proc_inst_id ←──→│ 纪检科 │
└──────┘ └──────────────┘ └────────────┘
不修改 BPMN 关联父子流程 独立的流程定义
一个会签人一个实例

主流程的定义完全不变。会签是一个独立的流程定义(比如 `countersign`),每个会签人启动一个独立的流程实例。主流程暂停在当前节点,等待所有会签完成。 ### hq 关联表 ```java public class hq extends BaseDao<hqMapper> { private String procInstId; private String matterName; private String taskId; private String deptId; private String userId; private String pass; private String cause; private String preProcInstId; private String enddate; private Date startTime; }

preProcInstId是整个方案的核心——它关联主流程实例.通过这个字段可以查出某个主流程实例下所有会签记录.
procInstId关联每个会签人的子流程实例.

完整流程拆解

1. 启动会签——在 completeG 中发起

当审批人在当前节点选择"会签"时,前端传过来会签人员列表.completeG()中调用processService.start()为每个会签人启动一个独立的流程实例:

Stringkey=String.valueOf(center.getParameters("key"));Stringuserid=String.valueOf(center.getParameters("userid"));HashMap<String,String>tasks=processService.start(key,userid);StringtaskId=tasks.get("id");Stringinsid=tasks.get("insid");center.setParameters("taskid",taskId);center.setParameters("insid",insid);

processService.start()做的事情:

  • 启动一个独立流程定义(比如countersign
  • 自动走到第一个用户任务
  • 把第一个任务分配给指定的会签人

每启动一个子流程,在hq表里插入一条记录,关联父子流程

  • preProcInstId= 当前主流程实例ID
  • procInstId= 新启动的子流程实例ID
  • userId= 会签人
  • pass= null(未处理)
  • enddate= null(未完成)

2. 主流程等待——判断会签是否全部完成

主流程停在当前节点不走.当前端查询会签进度时,gethqinfo()hq表:

hq dao=newhq();dao.setSearchMethod("selectC");dao.setPreProcInstId(insid);List<hq>list=(List<hq>)dao.search();intcount=Integer.parseInt(list.get(0).getTaskId());

selectC查的是当前主流程实例下还有多少会签未完成。如果 count > 0,说明还有人没签完,主流程继续等.
gethqinfo()同时查所有会签记录的详情:

dao.setSearchMethod("selectAll");dao.setPreProcInstId(insid);list=(List<hq>)dao.search();

然后遍历每条记录,填充会签信息

  • 鹨门`(通过 userId 查用户表)
  • 会签结果(通过/不通过/未签批/放弃)
  • 会签意见
  • 签批时间
Stringtemp="1".equals(list.get(i).getPass())?"通过":"不通过";Stringyj=list.get(i).getCause();Stringdate1=list.get(i).getEnddate();if(date1==null||"".equals(date1)||"null".equals(date1)||"null".equals(date1)){row.setItemValue("result","未签批");}elseif("null".equals(list.get(i).getProcInstId())){row.setItemValue("result","放弃");}else{row.setItemValue("result",temp);row.setItemValue("cause",yj);row.setItemValue("rtime",date1);}

四种状态:未签批(还没处理)、通过不通过放弃(放弃了会签)。

判断主流程是否能继续走:

booleancanNext=true;if(count>0){canNext=false;}if("0".equals(list.get(i).getPass())){canNext=false;}

canNext为 true 时主流程才能继续走到下一个节点,为 false 时继续停在当前节点.

3. 会签人处理自己的会签任务

每个会签人在自己的待办列表里看到一个会签任务。打开后看到的是会签子流程的表单(不是主流程的表单)。处理完后

  • 子流程走完(完成当前任务)
  • 更新hq表:pass= “1” 或 “0”,cause= 意见,enddate= 当前时间
    处理完后,子流程结束。主流程那边通过hq表查询知道这个会签人处理完了。

4. 放弃会签——giveup()

如果会签人觉得不需要自己签(比如不相关的业务),可以放弃:

publicDataCentergiveup(DataCentercenter,...){processService.passProcessNoData(center,request,response);}

放弃后,子流程直接结束。hq表里procInstId碍为 null(或空),标记这条记录为"放弃"。

5. 回溯会签——gethq()

会签人打开会签任务时,需要加载主流程的表单数据(因为会签人要看原始申请内容才能做判断)。gethq()方法通过pre_proc_inst_id反查主流程实例ID,再加载对应的表单

publicHashMap<String,String>gethq(Stringinsid,Stringfromid)throwsException{Stringsqlid=list.get(0).getSqlid();ds.setParameter("proc_inst_id_",insid);DataCenterdc=sqlcl.CommonQuery(center,request,response);insid=ds1.getRowset().getrow(0).getItemStringValue("pre_proc_inst_id_");map.put("insid",insid);map.put("formid",processService.getTaskFormInsId(insid));returnmap;}

会签人从自己的子流程实例出发,通过pre_proc_inst_id找到主流程实例,再加载主流程的表单数据.这样会签人能看到原始申请内容.

为什么这样做

为什么不用 Activiti 的 multiInstance?

Activiti 5.13 的multiInstance(多实例)有三个硬伤:

  1. 参与者写死在 BPMN 里:流程定义时就确定好了谁参与会签,运行时不能改
  2. 必须修改流程定义:要在主流程 BPMN 里加一个multiInstance节点,改动成本高
  3. 一票否决等规则不灵活:multiInstance 的完成条件要么全部完成,要么按比例完成,政务场景的规则经常变

为什么外挂独立流程更好?

  1. 主流程 BPMN 不需要改:主流程的定义里没有会签节点,会签是运行时动态决定的
  2. 参与者动态指定:前端选择谁会签就启动谁的子流程,下次换人了也不需要改 BPMN
  3. 规则在代码里控制:canNext的判断逻辑可以随意定制——一票否决、全部通过/多数通过/任何自定义规则
  4. 可以加签/减签:追加会签人就在hq表里加记录,减少会签人就是删记录,不需要改 BPMN
  5. 任何节点都能会签:不管主流程走到哪个环节,都能发起会签,因为会签是外挂的,不影响主流程定义
  6. 会签人独立操作:每个会签人有自己的流程实例,可以独立处理/放弃/不影响其他人

为什么用 hq 表而不是流程变量?

Activiti 的流程变量( processVariables)是和流程实例绑定的.会签的子流程和主流程是不同的流程实例,流程变量不共享.用数据库表关联是最简单直接的——父子流程实例ID 一关联,查询方便,不会丢失。

决策原则

不修改主流程定义,用外挂的方式实现会签——主流程的 BPMN 里没有会签节点,会签是运行时的动作而不是设计时的约束。
政务系统的特点是流程定义稳定、但参与人员经常变.把"谁参与"这个决策从设计时推迟到运行时,解决了改 BPMN 才能部署的问题。也方便了加签/减签、规则调整——只需要改代码和不需要改流程定义。

你的项目里流程追踪是怎么做的?是用 multiInstance 还是其他方案?欢迎评论区聊聊。

作者:许彰午| 非科班野生程序员,深耕政务信息化20年

标签:#Java #Activiti #工作流 #会签 #外挂流程 #政务信息化

http://www.jsqmd.com/news/626927/

相关文章:

  • Docker 容器中运行 AI CLI 工具:用户隔离与持久化卷实战指南嫌
  • AI推理服务限流不是加个RateLimiter就完事了,深度拆解7类LLM调用特征与动态熔断阈值计算公式(含Go/Python双实现)
  • 从手机聊天记录到硬盘镜像:给程序员的5个电子取证实战入门技巧
  • Python的类方法与静态方法在面向对象设计中的职责划分原则
  • LPC55S69嵌入式FAT文件系统实战:SDIO+FatFs+FreeRTOS集成指南
  • VMware vSphere 云平台运维与管理基础——第3章:VMware vSphere iSCSI 共享存储搭建与挂载(StarWind + Openfiler + ESXi)
  • Python的__del__方法:析构函数的陷阱与替代方案
  • SITS2026闭门报告首度流出:AI原生MES的5大硬核能力清单(附3家头部车企验证数据)
  • 用 Microsoft Agent Framework 构建 SubAgent(Multi-Agent)赐
  • 图像识别实战错误监控体系
  • HunyuanVideo-Foley音效生成实战:集成Python爬虫构建影视素材库
  • 数据库架构演进
  • 特征选择三剑客:过滤法、包装法与嵌入法的实战对比
  • 2026年质量好的中频炉精选推荐公司 - 品牌宣传支持者
  • 阅读《人月神话》与《代码大全》在2024年的新感悟
  • SGM58200 AD采样在嵌入式系统中的三种高效采集方案实现
  • watgo发布:Go语言打造WebAssembly工具包的新突破
  • 移动性能监控区块链隐私
  • SpringCloud进阶--Sentinel 流量防卫兵官
  • 软件风险管理中的应对策略制定
  • 2026年4月专业的贯通式货架工厂推荐,重型货架/仓储货架/贯通货架/横梁货架/库房货架,贯通式货架实力厂家推荐 - 品牌推荐师
  • VS Code 扩展支持 Swift 语言开发
  • 云原生可观测性:构建透明的云原生系统
  • Jenkins 学习总结恢
  • 阿里通义Z-Image-GGUF体验:中英文提示词生成精美图片实测
  • AS5048旋转编码器SPI驱动设计与嵌入式工程实践
  • 腾讯ESG报告:构建未成年人网络保护协同体系
  • GPUStack 在华为昇腾 I A 服务器上的保姆级部署指南不
  • 大模型API高并发失控真相(限流策略失效导致P99延迟飙升400ms+):基于Llama 3微服务栈的熔断决策树实战推演
  • 深度解析AI Agent的异常处理机制:从容错设计到自动恢复的完整链路