Flowable05员工请假流程的接口开发---------------------持续更新中

下面,我将以我们之前创建的“员工请假流程”为例,分步详解如何操作一个流程。
具体BPMN文件如下 :

<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef" exporter="Flowable Open Source Modeler" exporterVersion="6.8.0">
  <process id="leaveRequestProcess" name="员工请假流程" isExecutable="true">
    <startEvent id="startEvent" name="开始" flowable:initiator="initiator"></startEvent>
    <userTask id="submitLeaveRequestTask" name="提交请假申请" flowable:assignee="${initiator}" flowable:formKey="leave-form">
      <documentation>员工填写并提交请假表单,包含请假天数、事由等信息。</documentation>
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <userTask id="managerApprovalTask" name="经理审批" flowable:candidateGroups="managers" flowable:formKey="approval-form">
      <documentation>直属经理审核请假申请。完成后需要设置流程变量 'approved' (布尔值: truefalse)</documentation>
    </userTask>
    <exclusiveGateway id="approvalDecisionGateway" name="审批决定"></exclusiveGateway>
    <serviceTask id="notifyRejectionTask" name="通知申请人结果" flowable:class="com.example.flowable.delegate.NotifyApplicantDelegate">
      <documentation>当申请被驳回时,自动向申请人发送通知。</documentation>
    </serviceTask>
    <endEvent id="endEventApproved" name="流程结束 (批准)"></endEvent>
    <endEvent id="endEventRejected" name="流程结束 (驳回)"></endEvent>
    <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="submitLeaveRequestTask"></sequenceFlow>
    <sequenceFlow id="flow2" sourceRef="submitLeaveRequestTask" targetRef="managerApprovalTask"></sequenceFlow>
    <sequenceFlow id="flow3" sourceRef="managerApprovalTask" targetRef="approvalDecisionGateway"></sequenceFlow>
    <sequenceFlow id="flowToApproved" name="批准" sourceRef="approvalDecisionGateway" targetRef="endEventApproved">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved == true}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flowToRejected" name="驳回" sourceRef="approvalDecisionGateway" targetRef="notifyRejectionTask">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved == false}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flowAfterRejection" sourceRef="notifyRejectionTask" targetRef="endEventRejected"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_leaveRequestProcess">
    <bpmndi:BPMNPlane bpmnElement="leaveRequestProcess" id="BPMNPlane_leaveRequestProcess">
      <bpmndi:BPMNShape bpmnElement="startEvent" id="BPMNShape_startEvent">
        <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="submitLeaveRequestTask" id="BPMNShape_submitLeaveRequestTask">
        <omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="managerApprovalTask" id="BPMNShape_managerApprovalTask">
        <omgdc:Bounds height="80.0" width="100.0" x="325.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="approvalDecisionGateway" id="BPMNShape_approvalDecisionGateway">
        <omgdc:Bounds height="40.0" width="40.0" x="475.0" y="158.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="notifyRejectionTask" id="BPMNShape_notifyRejectionTask">
        <omgdc:Bounds height="80.0" width="100.0" x="565.0" y="230.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endEventApproved" id="BPMNShape_endEventApproved">
        <omgdc:Bounds height="28.0" width="28.0" x="600.0" y="164.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endEventRejected" id="BPMNShape_endEventRejected">
        <omgdc:Bounds height="28.0" width="28.0" x="715.0" y="256.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flowToRejected" id="BPMNEdge_flowToRejected" flowable:sourceDockerX="20.0" flowable:sourceDockerY="20.0" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
        <omgdi:waypoint x="495.0" y="197.93916938110752"></omgdi:waypoint>
        <omgdi:waypoint x="495.0" y="270.0"></omgdi:waypoint>
        <omgdi:waypoint x="565.0" y="270.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1" flowable:sourceDockerX="15.0" flowable:sourceDockerY="15.0" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
        <omgdi:waypoint x="129.9499984899576" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="174.9999999999917" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="50.0" flowable:targetDockerY="40.0">
        <omgdi:waypoint x="274.9499999999581" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="324.9999999999364" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="20.0" flowable:targetDockerY="20.0">
        <omgdi:waypoint x="424.95000000000005" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="475.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flowAfterRejection" id="BPMNEdge_flowAfterRejection" flowable:sourceDockerX="50.0" flowable:sourceDockerY="40.0" flowable:targetDockerX="14.0" flowable:targetDockerY="14.0">
        <omgdi:waypoint x="664.949999999996" y="270.0"></omgdi:waypoint>
        <omgdi:waypoint x="715.0" y="270.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flowToApproved" id="BPMNEdge_flowToApproved" flowable:sourceDockerX="20.0" flowable:sourceDockerY="20.0" flowable:targetDockerX="14.0" flowable:targetDockerY="14.0">
        <omgdi:waypoint x="514.9416246851385" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="600.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

现在,我们来一步步走完“员工请假流程”。
步骤 1:启动一个流程实例
当一个员工想要请假时,我们就需要为他启动一个新的流程实例。
使用服务:RuntimeService
关键方法:startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables)
processDefinitionKey: 流程定义的 id,在我们的 BPMN 文件中是 leaveRequestProcess。
variables: 一个 Map,用于传入流程变量 (Process Variables)。这些变量在整个流程实例的生命周期中都可用。
假设我们创建一个 REST 接口来启动流程。

@RestController
@RequestMapping("/leave")
public class LeaveProcessController {

    @Autowired
    private RuntimeService runtimeService;

    @PostMapping("/start")
    public String startLeaveProcess(@RequestParam String userId) {
        // 设置流程变量
        Map<String, Object> variables = new HashMap<>();
        // BPMN中定义的 flowable:initiator="initiator" 会自动将发起人ID存入此变量
        // 这里我们也可以手动设置,或者设置其他业务变量
        variables.put("initiator", userId); 
        variables.put("reason", "家庭急事需要请假3天"); // 比如请假事由
        
        // 使用流程定义的 Key 启动流程
        // Key 就是 BPMN 文件中 <process> 标签的 id 属性
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveRequestProcess", variables);

        return "请假流程已成功启动,流程实例ID: " + processInstance.getId();
    }
}

这样我们的流程就已经启动。

步骤 2:查询并处理用户任务
现在,流程停在了某个用户的待办事项中。用户需要查询属于自己的任务,并完成它。
使用服务:TaskService
关键方法:createTaskQuery()
示例代码:
查询指定用户的待办任务列表。

@GetMapping("/tasks")
public List<Map<String, String>> getMyTasks(@RequestParam String userId) {
    // 创建任务查询
    List<Task> tasks = taskService.createTaskQuery()
            .taskAssignee(userId) // 查询分配给该用户的任务
            .orderByTaskCreateTime().desc() // 按创建时间降序排序
            .list(); // 获取列表

    // 简化返回结果
    return tasks.stream().map(task -> {
        Map<String, String> map = new HashMap<>();
        map.put("taskId", task.getId());
        map.put("taskName", task.getName());
        return map;
    }).collect(Collectors.toList());
}

在“经理审批”节点,我们设置的是 candidateGroups=“managers”。这意味着任务属于 managers 组,组内任何人都看得到,但需要先认领 (Claim) 才能处理。(ps:这里先不需要理解组整个概念,下章节主要讲解整个地方)

// 假设一个经理 'managerA' 决定处理这个任务
taskService.claim(taskId, "managerA");

认领后,这个任务的 assignee 就变成了 managerA,其他经理就无法再处理了。
完成任务是推动流程前进的关键。
使用服务:TaskService
关键方法:complete(String taskId, Map<String, Object> variables)
示例代码:
经理审批并完成任务。这一步至关重要,因为他需要设置流程变量 approved 来驱动后续的排他网关。

@PostMapping("/tasks/{taskId}/complete")
public String completeTask(@PathVariable String taskId, @RequestParam boolean approved) {
    // 检查任务是否存在
    Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    if (task == "null") {
        return "任务不存在或已被处理";
    }

    // 设置流程变量,用于网关判断
    Map<String, Object> variables = new HashMap<>();
    variables.put("approved", approved);

    // 完成任务,并传入流程变量
    taskService.complete(taskId, variables);

    return "任务 " + taskId + " 已成功处理!";
}

当经理调用这个接口并传入 approved=true 时,流程引擎在完成任务后,会根据条件 ${approved == true} 让流程走向“批准”路径;反之,则走向“驳回”路径。

步骤 3:查询流程历史

当流程结束后(无论是批准还是驳回),它就从“运行时”数据变成了“历史”数据。我们可以通过 HistoryService 来查询。
使用服务:HistoryService
关键方法:createHistoricProcessInstanceQuery()
示例代码:
查询某个已完成的流程实例信息。

@GetMapping("/history/{processInstanceId}")
public HistoricProcessInstance getHistory(@PathVariable String processInstanceId) {
    return historyService.createHistoricProcessInstanceQuery()
            .processInstanceId(processInstanceId)
            .finished() // 确保查询的是已完成的实例
            .singleResult(); // 获取单个结果
}

操作一个流程的本质,就是通过调用 Flowable 提供的各种 Service API,来与流程引擎进行交互。整个过程可以概括为:

启动:使用 RuntimeService 根据流程定义的 Key 启动一个流程实例,并可以传入初始的流程变量。
推进:使用 TaskService 查询 分配给用户或用户组的任务,然后完成它,同时可以传入新的流程变量来影响流程走向。
查询:在流程运行期间使用 RuntimeService 查询状态,在流程结束后使用 HistoryService 查询执行记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值