简介工作流请假实例是一套基于Struts2的Java Web工作流入门资料适合正在学习工作流建模、MVC框架及企业请假流程开发的初学者也可用于高校课程设计或毕业设计参考。案例完整覆盖员工提交请假申请、主管审批、人力资源记录等核心业务环节并针对Java Web开发中常见的中文乱码问题给出了编码配置与处理思路有助于避免因字符集不一致导致的页面显示异常。压缩包共42个文件大小仅51KB包含12个XML配置文件、8个JSP页面、Java源码与class文件、properties属性文件及相关资源覆盖流程定义、动作映射、页面展示、数据库访问多个层面目录划分清晰便于按模块阅读和运行。已有250人学习浏览可作为工作流引擎与Web框架集成实践的入门练手材料。通过研究源码与配置可理解请假流程如何建模、请求如何分发与审批、数据如何读写也能据此快速搭建可运行、可扩展的请假审批原型为后续复杂业务流程开发积累经验。 一张请假单就是最经典的工作流请假实例。很多团队第一次接触工作流不是从购买高昂的BPM产品开始而是从给OA系统加一个“请假审批”开始。我自己的经历也是这样工作第七年第一次正儿八经设计工作流做的就是请假流程工具从Activiti换到Flowable后来又陆续研究过Camunda、n8n、Dify、Coze这些方案绕了一大圈回来发现请假看起来简单但它把工作流的核心要素全占齐了节点、条件、角色、超时、会签/或签、流程审计一样不缺。这篇文章就以“工作流请假实例”为主线把从需求分析、技术选型、流程建模到落地排坑的完整路径摊开来讲适合正在做OA、HR系统或者内部管理工具的朋友参考。1. 请假流程为什么值得用工作流引擎1.1 一张请假单背后的流程痛点先说需求本身。小团队觉得请假很简单员工跟主管说一声主管同意就行。但公司人数一过百规则立刻变复杂。不同职级的人审批链不一样普通员工请假3天以内主管批、3到7天部门经理加批、高管请假可能要走到CEO同一个部门的人请假可能需要另一个部门负责人会签确认工作交接超过5天还要抄送HR记录调休或年假扣减。这些规则靠人去记很容易漏。我见过最原始的做法是Excel加邮件人事每周五手工统计请假单月底再和考勤核对。这种方式的问题不只是效率低更严重的是流程不可控。谁能批、批到第几步、超时了找谁全靠人的自觉。一旦某个业务负责人休假审批就悬在半空员工不好意思催HR也查不到单子卡在哪一环。需求痛点非常明确请假流程需要一个能把“规则”和“执行”分开、把流转历史完整记录下来的东西这就是工作流引擎最擅长解决的事。1.2 工作流引擎解决的核心问题工作流引擎的核心逻辑说穿了就是“状态机加规则”。它把请假单抽象成一系列状态已提交、审批中、已通过、已拒绝、已撤销、已超时然后通过预定义的规则决定状态如何迁移、谁有权限触发迁移、迁移后通知谁。这里面有几个容易被忽略的关键设计点。第一是审批人的动态解析不是写死某个用户名而是通过角色、部门、汇报关系甚至自定义表达式实时算出当前节点该由谁处理。第二是分支条件根据请假天数、请假类型年假、事假、病假、调休走不同的审批链。第三是超时提醒审批人超过N小时未处理时系统自动提醒或转交。第四是审计追踪谁在什么时间做了什么操作这些数据不光是合规需要也是后续做人力分析的基础。这些点单独看抽象放到具体实例里就很容易理解了。2. 技术选型不同场景下的工作流方案对比2.1 重量级BPM引擎Flowable/Camunda如果请假流程要跟现有OA、HR、ERP系统深度集成流程复杂度高需要并发会签、子流程、条件网关这些能力Flowable和Camunda这类BPMN 2.0引擎是首选。Flowable是从Activiti 5分支出来的API稳定社区庞大国内使用的团队非常多。Camunda的建模工具体验更好BPMN可视化做得漂亮运维监控面板比Flowable更直观。两者都支持BPMN 2.0标准意味着流程定义文件XML是标准化的后续迁移成本相对可控。我个人的建议是团队熟悉Java、需要深度二次开发选Flowable如果更看重流程建模的协作体验和线上监控能力选Camunda。但这两个引擎的上手门槛都不低部署、数据表初始化、监听器配置、身份体系对接至少要预留一到两周专门做技术接入。2.2 轻量级与AI工作流Dify/n8n/Coze如果请假流程只是内部小范围使用比如几十个人的团队或者你手里根本没有专门的开发资源那就别上BPM引擎这套重型方案了。n8n、Dify、Coze这类工作流工具提供了可视化的节点编排表单、审批、通知、数据存储基本都能以拖拽方式搭出来实现一个请假审批几乎不用写代码。Dify本身更偏向LLM应用的工作流平台但它的工作流编排器并不限制场景可以做表单收集和节点分发适合想在请假流程里加入AI能力的人比如让AI自动判断请假类型、自动检查团队排班冲突。Coze是字节出的智能体平台优势是生态完善接飞书、企微、钉钉通知非常方便。n8n是自托管的自动化工具强在扩展性接数据库、接API非常灵活。这三者的共同特点适合“流程不重、上线要快、MVP验证”的场景但对BPMN标准的支持、事务性保证、高并发能力都偏弱流程一旦复杂起来会很难维护。2.3 选型决策表我把常见的选型思路整理成一张表方便直接对号入座场景推荐方案理由企业级OA/HR系统Java技术栈流程复杂Flowable / Camunda支持BPMN标准、会签、子流程事务性强轻量级内部工具几十人团队无专业开发n8n / Coze / 飞书审批上线快、免运维、支持表单与通知需要AI能力如自动分类、智能审批建议Dify / Coze工作流节点可接入LLM扩展灵活已有遗留系统只是审批环节需要规范化轻量状态机加消息通知不需要额外引擎避免架构膨胀选型时我有一条底线不要为了“用工作流”而引入工作流。如果公司已经有成熟的飞书或企微审批能力那个“请假单”可能根本不需要自研直接用现成应用就能解决。只有当你要自定义复杂审批规则、深度集成内部系统或者对流程数据有强审计需求时才值得自己搭。3. 请假工作流的建模与关键设计3.1 节点定义与流转条件不管用什么引擎请假流程的建模思路是通用的。我以一个比较典型的中型公司场景为例流程节点按顺序走提交申请、主管审批、部门经理审批、HR复核、工作交接会签、结束。其中部门经理审批和HR复核不是每次都出现需要根据条件动态决定。我通常会这样设计流转条件请假时长小于等于3天且类型为年假、病假、调休主管审批通过后直接结束抄送HR。请假时长大于3天主管通过后进入部门经理审批。类型为事假无论时长主管通过后都进入HR复核因为事假通常需要人工确认原因。时长超过5天或涉及年假进入HR复核同时校验剩余额度。在BPMN里这些条件写在网关Gateway的流转线上。Flowable用UEL表达式Camunda可以用UEL或FEELn8n里直接写JavaScript。表达式看似简单但实际坑不少后面第5章会专门列问题。3.2 审批模式或签、会签、依次审批请假流程里常见的审批模式有3种别搞混依次审批A批完给BB批完给C。适用于层级链比如主管、经理、HR逐级处理。或签多人同时待审其中任一人通过则本节点通过任一人拒绝则本节点拒绝。适用于“找到一个负责人即可”的场景比如两位同级的副经理谁批都可以。会签多人同时待审必须所有人都通过才进入下一步任何人拒绝则驳回。适用于工作交接确认比如交接人和部门同事都需要确认。实现上的区别不小。Flowable里或签可以通过多实例Multi-Instance并配合isSequentialfalse和completionCondition实现会签同样是多实例但完成条件要改成“所有实例完成且全部通过”。这里最容易被坑的是“拒绝”的判定逻辑或签有人拒绝流程是直接结束还是等其他人也审批完再结束这个必须在设计时想清楚并且在网关里显式建模否则就会出现“明明有人拒绝了流程还在跑”的诡异现象。3.3 超时与异常处理设计请假审批最烦的就是卡在某个审批人手里。超时机制一定要设计每个审批节点都建议挂一个超时任务比如48小时未处理先发一次提醒72小时未处理自动转交给上级或者标记为“已逾期”由HR人工介入。关于自动通过策略我持保留态度。有不少团队图省事超时直接自动通过结果个别员工专门卡主管审批时间来“默认获批”出了事解释不清。更稳妥的做法是超时自动提醒加升级而不是自动通过如果业务上确实需要自动批准必须保留完整的审批链和超时记录并向员工明示规则。异常处理的场景还包括员工提交后想撤回修改、审批人离职导致角色无人处理、流程实例被误操作删除等。这些在设计数据模型和API时就要考虑进去别等上线了再补否则临时加逻辑非常痛苦。4. 实操基于Flowable落地一个请假流程4.1 流程定义文件BPMN示例下面这个例子是我在自己项目里跑通过的一个简化版请假流程基于Flowable 6.x。流程结构是提交申请、主管审批、判断是否超过3天、部门经理审批、判断是否需要HR复核、HR复核、结束。为了便于展示这里给出关键的BPMN XML片段?xml version1.0 encodingUTF-8? definitions xmlnshttp://www.omg.org/spec/BPMN/20100524/MODEL xmlns:flowablehttp://flowable.org/bpmn targetNamespacehttp://flowable.org/bpmn process idleaveProcess name请假审批流程 isExecutabletrue startEvent idstartLeave name提交申请 flowable:formKeyleaveForm / userTask idmanagerApprove name主管审批 flowable:assignee${manager} / exclusiveGateway idgtwLongLeave name是否超过3天 / userTask iddeptApprove name部门经理审批 flowable:candidateGroupsdept_manager / exclusiveGateway idgtwHR name是否需要HR复核 / userTask idhrApprove nameHR复核 flowable:candidateGroupshr / endEvent idendLeave name结束 / sequenceFlow idflow1 sourceRefstartLeave targetRefmanagerApprove / sequenceFlow idflow2 sourceRefmanagerApprove targetRefgtwLongLeave / sequenceFlow idflow3 sourceRefgtwLongLeave targetRefdeptApprove conditionExpression xsi:typetFormalExpression${leaveDays gt; 3}/conditionExpression /sequenceFlow sequenceFlow idflow4 sourceRefgtwLongLeave targetRefgtwHR conditionExpression xsi:typetFormalExpression${leaveDays lt; 3}/conditionExpression /sequenceFlow sequenceFlow idflow5 sourceRefdeptApprove targetRefgtwHR / sequenceFlow idflow6 sourceRefgtwHR targetRefhrApprove conditionExpression xsi:typetFormalExpression${leaveType PERSONAL || leaveDays gt; 5}/conditionExpression /sequenceFlow sequenceFlow idflow7 sourceRefgtwHR targetRefendLeave conditionExpression xsi:typetFormalExpression${leaveType ! PERSONAL amp;amp; leaveDays lt; 5}/conditionExpression /sequenceFlow sequenceFlow idflow8 sourceRefhrApprove targetRefendLeave / /process /definitions注意几个细节manager这个变量是启动流程时动态传入的由接口根据当前登录用户的上级关系计算出来candidateGroups是角色组dept_manager和hr需要在引擎的身份表里提前配置。另外一个非常容易忽略的点是在BPMN XML中大于号要写成gt;与号要写成amp;否则不符合XML规范部署流程定义时会被解析器拦下来。4.2 关键配置说明流程定义部署成功只是第一步真正决定流程能不能跑顺的是下面几个配置。第一启动流程实例时业务ID要跟内部请假单ID绑定。Flowable里建议用businessKey字段存业务单号这样在查询、关联、生成报表时都能方便地关联到业务表。第二审批人表达式里的变量来源要规范。我在项目里定的规范是所有动态审批人比如manager必须在启动流程时或任务创建时一次性通过流程变量写好不要在任务执行过程中反复修改变量否则会出现并发问题——两个任务同时读写变量结果互相覆盖审批人莫名其妙变成另一个人。第三表单数据不要全部塞进流程变量。有人图省事把请假单所有字段都当成流程变量存到引擎的变量表里结果历史表每天涨几百M。正确做法是流程变量只存流程控制必需的字段leaveDays、leaveType、manager、businessKey其他业务数据存业务表通过businessKey关联。不然等流程量上来你会被数据库性能问题折磨到怀疑人生。4.3 表单与业务数据打通前端表单提交后后端接口需要做的事情可以列成一套标准处理链校验业务合法性检查剩余假期额度、时间冲突、是否重复提交。插入业务表leave_record状态置为DRAFT。构建流程变量manager、leaveDays、leaveType、businessKey。调用runtimeService.startProcessInstanceByKey(leaveProcess, businessKey, variables)。把流程实例ID写回业务表状态置为PENDING。审批人点击通过或拒绝实际上就是调用taskService.complete(taskId, variables)同时更新业务表状态。这种“业务表状态加引擎任务状态”的双写方式是踩了不少坑之后总结出来的最佳实践引擎状态面向流程控制业务表状态面向查询展示两者通过businessKey关联保持最终一致。如果只依赖引擎的状态业务查询会变得非常别扭而且引擎的表结构对业务方来说很不友好。5. 常见问题与排查技巧实录5.1 流程启动后卡在第一个节点不动这是最经典的新手问题。流程启动了任务也生成了但审批人看不到待办。排查思路按顺序来查引擎的任务表看assignee和candidate字段有没有值。如果assignee为空说明表达式${manager}没有解析出结果重点查启动流程时是否传了这个变量。如果assignee非空但用户看不到十有八九是用户体系没同步引擎表里的用户ID和你们系统用户ID不一致。查引擎日志看任务创建时有没有抛异常。这条经验的价值在于工作流引擎不是黑盒流程出问题要从“变量解析”“身份同步”“任务生成”三个层次去定位而不是一上来就怀疑引擎坏了。5.2 条件分支走错路排他网关条件不命中时Flowable默认会抛异常报错信息大致是“无法为排他网关选择出线”。这个报错本身很直白但实际中更多见的是条件写法错误。比如在项目里见过有人把leaveDays 3写成了leaveDays 3字符串和数字比较结果条件永远不成立所有流程都走了默认分支。排查工具方面Flowable的ACT_RU_EXECUTION表可以直接看到当前流程走到了哪个节点结合ACT_HI_ACTINST看历史轨迹。有条件的话在网关前加一个日志服务任务把关键变量的值打印出来比事后对着数据库猜要快得多。5.3 审批人角色匹配不到人candidateGroups配置了角色名但引擎里没有创建对应的组和组成员关系导致任务挂在角色下却没有实际的人能处理。解决方式有两个一是用引擎自带的IdentityService在部署时初始化角色和关系二是直接对接公司现有的人员组织架构在任务创建时把人算好放进candidateUsers不走引擎的角色体系。我更推荐第二种原因是能复用公司现有的组织架构和岗位级别避免维护两套身份体系。这个在大公司尤其重要你不可能让HR在引擎管理界面里手动维护人员角色那本身就是一场灾难。5.4 引擎版本升级与数据迁移Flowable从5.x升级到6.x数据表结构和历史数据迁移是个大工程。我吃过亏当时只看了官方文档说“支持直接升级”结果在生产库执行升级脚本后部分历史流程实例的变量丢失。后来团队定下的策略是升级前先在一个完整备份的库上跑一遍升级脚本对比ACT_HI_*历史表的行数和关键字段确认无误后再动生产升级期间停掉所有启动新流程的入口避免新旧版本数据混写。这个建议同样适用于Camunda和Activiti。别光信文档里写的“平滑升级”数据迁移永远值得你用最笨的方法验证一遍尤其是历史流程数据这种不可再生的东西。6. 扩展轻量级方案怎么把请假流程跑起来6.1 n8n的等待回调实现思路如果你最终选择的是n8n这类轻量工具流程建模的思路不变但实现方式差异很大。以n8n为例用Webhook节点接收表单提交判断请假天数用IF节点发送审批请求用Wait节点挂起流程审批人点击后通过Webhook回调恢复流程最后发送通知可以用邮件、企业微信机器人或钉钉机器人。整个过程不需要写BPMN XML但你要自己想清楚“等待-恢复”机制怎么保证可靠。比如服务器重启后挂起的任务会不会丢回调地址是否需要开启认证审批数据是存在节点上下文里还是外部数据库。轻量方案的维护成本不在写流程而在把这些边界问题想全。6.2 Coze/飞书侧的快速落地玩法Coze那边更简单表单收集、节点分支、消息通知都是内置能力请假流程甚至可以做到员工在飞书群里填个表单AI自动整理信息并推送审批卡片。这种方案的好处是几小时就能上线坏处是流程一旦复杂可视化画布会变得非常混乱节点与节点之间的依赖关系很难维护。我的定位建议是把轻量方案作为部门级工具来用而不是公司级中台。当你发现节点超过20个、条件分支超过10条、需要跨系统数据同步的时候就是时候切换到Flowable或Camunda这类更正规的引擎了。做请假这个工作流实例我最大的体会是工作流的本质不是“把流程图画出来”而是“把流程规则显性化、可执行、可追踪”。流程图再漂亮如果审批人解析、条件分支、超时处理这些细节没想清楚上线后照样一地鸡毛。如果让我给一个落地清单核心就是三件事第一把审批人算对这是使用体验的命门第二把失败路径设计全包括拒绝、撤回、超时、角色缺失这些不常走但一定会走到的路第三做好数据分离流程变量和业务数据不要混在一起存储。想清楚这三点不管用Flowable、n8n还是Coze请假流程都能稳定跑起来。本文还有配套的精品资源点击获取