java每日精进 3.19 【工作流】

1.简介

Java 项目中的工作流(Workflow)通常指的是业务流程的自动化管理,涉及多个步骤、状态和参与者。

工作流引擎(如 ActivitiCamundajBPM)可以帮助开发者定义、执行和监控这些流程。

2.工作流应用场景


具体场景,凡是涉及到业务流程的所有场景

关键业务流程:订单、报价处理、合同审核、客户电话处理、供应链管理等。行政管理类:出差申请、加班申请、请假申请、用车申请、各种办公用品申请、购买申请、日报周报等凡是原来手工流转处理的行政表单。。人事管理类:员工培训安排、绩效考评、职位变动处理、员工档案信息管理等。财务相关类:付款请求、应收款处理、日常报销处理、出差报销、预算和计划申请等.。客户服务类:客户信息管理、客户投诉、请求处理、售后服务管理等。

3.工作流的核心概念

3.1 流程定义(Process Definition)

  • 流程定义是工作流的蓝图,通常用 BPMN 2.0(Business Process Model and Notation)标准定义。

  • 它描述了流程的步骤、顺序、条件、参与者等。

3.2 流程实例(Process Instance)

  • 流程实例是流程定义的一个具体执行实例。

  • 每个实例都有自己的状态和数据。

3.3 任务(Task)

  • 任务是流程中的一个步骤,可以是用户任务(需要人工干预)或服务任务(自动执行)。

3.4 网关(Gateway)

  • 网关用于控制流程的分支和合并,例如并行网关、排他网关等。

3.5 事件(Event)

  • 事件是流程中的触发点,例如开始事件、结束事件、中间事件等。

3.6 参与者(Actor)

  • 参与者是流程中执行任务的角色或用户。

4.简单示例

4.1Camunda 流程引擎实现

process.bpmn:

<bpmn:definitions
        xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL"
        xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
        xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
        xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
        xmlns:camunda="http://camunda.org/schema/1.0/bpmn"
        id="Definitions_1"
        targetNamespace="http://bpmn.io/schema/bpmn"
        exporter="Camunda Modeler"
        exporterVersion="5.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://camunda.org/schema/1.0/bpmn">

    <bpmn:process id="manuscriptApproval" name="Manuscript Approval Process" isExecutable="true">
        <!-- 稿件接收与登记 -->
        <bpmn:startEvent id="startEvent"/>
        <bpmn:sequenceFlow id="flow1" sourceRef="startEvent" targetRef="receiveAndRegister"/>
        <bpmn:serviceTask id="receiveAndRegister" name="Receive and Register"
                          camunda:class="com.home.tasks.ReceiveAndRegisterTask"/>

        <!-- 初审 -->
        <bpmn:sequenceFlow id="flow2" sourceRef="receiveAndRegister" targetRef="initialReview"/>
        <bpmn:userTask id="initialReview" name="Initial Review"/>

        <!-- 外审 -->
        <bpmn:sequenceFlow id="flow3" sourceRef="initialReview" targetRef="externalReview"/>
        <bpmn:userTask id="externalReview" name="External Review"/>

        <!-- 复审 -->
        <bpmn:sequenceFlow id="flow4" sourceRef="externalReview" targetRef="reReview"/>
        <bpmn:userTask id="reReview" name="Re-Review"/>

        <!-- 终审 -->
        <bpmn:sequenceFlow id="flow5" sourceRef="reReview" targetRef="finalReview"/>
        <bpmn:userTask id="finalReview" name="Final Review"/>

        <!-- 出版准备 -->
        <bpmn:sequenceFlow id="flow6" sourceRef="finalReview" targetRef="publishPreparation"/>
        <bpmn:serviceTask id="publishPreparation" name="Publish Preparation"
                          camunda:class="com.home.tasks.PublishPreparationTask"/>

        <!-- 出版与发行 -->
        <bpmn:sequenceFlow id="flow7" sourceRef="publishPreparation" targetRef="publishAndDistribute"/>
        <bpmn:serviceTask id="publishAndDistribute" name="Publish and Distribute"
                          camunda:class="com.home.tasks.PublishAndDistributeTask"/>

        <!-- 反馈与改进 -->
        <bpmn:sequenceFlow id="flow8" sourceRef="publishAndDistribute" targetRef="feedbackAndImprovement"/>
        <bpmn:serviceTask id="feedbackAndImprovement" name="Feedback and Improvement"
                          camunda:class="com.home.tasks.FeedbackAndImprovementTask"/>

        <!-- 结束 -->
        <bpmn:sequenceFlow id="flow9" sourceRef="feedbackAndImprovement" targetRef="endEvent"/>
        <bpmn:endEvent id="endEvent"/>
    </bpmn:process>

    <!-- 图形化布局(可选) -->
    <bpmndi:BPMNDiagram id="BPMNDiagram_1">
        <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="manuscriptApproval">
            <bpmndi:BPMNShape id="StartEvent_1_di" bpmnElement="startEvent">
                <dc:Bounds x="152" y="102" width="36" height="36"/>
            </bpmndi:BPMNShape>
            <!-- 其他节点的图形化布局 -->
        </bpmndi:BPMNPlane>
    </bpmndi:BPMNDiagram>
</bpmn:definitions>

application.properties:

spring.datasource.url=jdbc:h2:mem:camunda
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Camunda 管理员用户配置
camunda.bpm.admin-user.id=demo
camunda.bpm.admin-user.password=demo
camunda.bpm.admin-user.firstName=Demo
camunda.bpm.admin-user.lastName=Demo
@SpringBootApplication
public class WorkflowApplication implements CommandLineRunner {

    @Autowired
    private RuntimeService runtimeService;

    public static void main(String[] args) {
        SpringApplication.run(WorkflowApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        runtimeService.startProcessInstanceByKey("manuscriptApproval");
        System.out.println("稿件审批流程已启动!");
    }
}
@Service
public class ReceiveAndRegisterTask implements JavaDelegate {

    @Override
    public void execute(DelegateExecution delegateExecution) throws Exception {
        System.out.println("稿件已接收并登记!");
    }
}
@Service
public class PublishPreparationTask implements JavaDelegate {
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("出版准备中...");
    }
}
@Service
public class PublishAndDistributeTask implements JavaDelegate {
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("稿件已出版并发行!");
    }
}
@Service
public class FeedbackAndImprovementTask implements JavaDelegate {
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("收集反馈并改进流程...");
    }
}

4.2 Flowable 流程引擎实现

4.2.1 leave-process.bpmn20.xml 文件

Flowable 也支持 BPMN 2.0,因此大部分内容可以直接复用。只需要将 camunda 命名空间替换为 flowable 命名空间。

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
             xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:flowable="http://flowable.org/bpmn"
             targetNamespace="http://flowable.org/bpmn20">

    <process id="leaveProcess" name="员工请假流程" isExecutable="true">
        <!-- 启动事件 -->
        <startEvent id="start" name="申请请假">
            <extensionElements>
                <flowable:initiator value="employee"/>
            </extensionElements>
        </startEvent>

        <!-- 提交申请任务 -->
        <userTask id="applyTask" name="提交请假申请" flowable:assignee="${employee}"/>

        <!-- 决策网关 -->
        <exclusiveGateway id="decisionGateway"/>

        <!-- 经理审批任务 -->
        <userTask id="managerApprovalTask" name="经理审批" flowable:assignee="manager"/>

        <!-- 审批结果网关 -->
        <exclusiveGateway id="approvalGateway"/>

        <!-- 结束事件 -->
        <endEvent id="approved" name="审批通过"/>
        <endEvent id="rejected" name="审批拒绝"/>

        <!-- 流程连接 -->
        <sequenceFlow sourceRef="start" targetRef="applyTask"/>
        <sequenceFlow sourceRef="applyTask" targetRef="decisionGateway"/>
        <sequenceFlow sourceRef="decisionGateway" targetRef="managerApprovalTask"/>
        <sequenceFlow sourceRef="managerApprovalTask" targetRef="approvalGateway"/>

        <!-- 审批通过 -->
        <sequenceFlow sourceRef="approvalGateway" targetRef="approved">
            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved == true}]]></conditionExpression>
        </sequenceFlow>

        <!-- 审批拒绝 -->
        <sequenceFlow sourceRef="approvalGateway" targetRef="rejected">
            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved == false}]]></conditionExpression>
        </sequenceFlow>
    </process>
</definitions>
4.2.1.1. XML声明和命名空间
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
             xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:flowable="http://flowable.org/bpmn"
             targetNamespace="http://flowable.org/bpmn20">

运行 HTML

  • XML声明:指定了XML版本和编码。

  • 命名空间:定义了BPMN 2.0标准和其他相关命名空间,如bpmn2bpmndidc等。flowable命名空间用于Flowable BPM引擎的扩展。

4.2.1.2. 流程定义
<process id="leaveProcess" name="员工请假流程" isExecutable="true">

运行 HTML

  • id:流程的唯一标识符。

  • name:流程的名称。

  • isExecutable:表示该流程是否可执行。

4.2.1.3. 启动事件
<startEvent id="start" name="申请请假">
    <extensionElements>
        <flowable:initiator value="employee"/>
    </extensionElements>
</startEvent>

运行 HTML

  • startEvent:表示流程的起点。

  • id:启动事件的唯一标识符。

  • name:启动事件的名称。

  • flowable:initiator:指定流程的发起者,这里设置为employee

4.2.1.4. 用户任务
<userTask id="applyTask" name="提交请假申请" flowable:assignee="${employee}"/>

运行 HTML

  • userTask:表示需要用户执行的任务。

  • id:任务的唯一标识符。

  • name:任务的名称。

  • flowable:assignee:指定任务的执行者,这里使用表达式${employee},表示由流程发起者(员工)执行。

4.2.1.5. 决策网关
<exclusiveGateway id="decisionGateway"/>

运行 HTML

  • exclusiveGateway:表示一个排他网关,用于根据条件决定流程的走向。

  • id:网关的唯一标识符。

4.2.1.6. 经理审批任务
<userTask id="managerApprovalTask" name="经理审批" flowable:assignee="manager"/>

运行 HTML

  • userTask:表示需要经理审批的任务。

  • id:任务的唯一标识符。

  • name:任务的名称。

  • flowable:assignee:指定任务的执行者为manager

4.2.1.7. 审批结果网关
<exclusiveGateway id="approvalGateway"/>

运行 HTML

  • exclusiveGateway:表示一个排他网关,用于根据审批结果决定流程的走向。

  • id:网关的唯一标识符。

4.2.1.8. 结束事件
<endEvent id="approved" name="审批通过"/>
<endEvent id="rejected" name="审批拒绝"/>

运行 HTML

  • endEvent:表示流程的结束点。

  • id:结束事件的唯一标识符。

  • name:结束事件的名称。

4.2.1.9. 流程连接
<sequenceFlow sourceRef="start" targetRef="applyTask"/>
<sequenceFlow sourceRef="applyTask" targetRef="decisionGateway"/>
<sequenceFlow sourceRef="decisionGateway" targetRef="managerApprovalTask"/>
<sequenceFlow sourceRef="managerApprovalTask" targetRef="approvalGateway"/>

运行 HTML

  • sequenceFlow:表示流程中的顺序流,连接各个节点。

  • sourceRef:指定顺序流的源节点。

  • targetRef:指定顺序流的目标节点。

4.2.1.10. 条件表达式
<sequenceFlow sourceRef="approvalGateway" targetRef="approved">
    <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved == true}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="approvalGateway" targetRef="rejected">
    <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved == false}]]></conditionExpression>
</sequenceFlow>

运行 HTML

  • conditionExpression:用于定义条件表达式,决定流程的走向。

  • xsi:type="tFormalExpression":指定表达式类型为正式表达式。

  • CDATA:包含条件表达式,${approved == true}表示审批通过,${approved == false}表示审批拒绝。

总结

这段代码定义了一个简单的员工请假流程,包括以下步骤:

  1. 员工发起请假申请。

  2. 提交请假申请。

  3. 流程进入决策网关。

  4. 经理审批请假申请。

  5. 根据审批结果,流程进入相应的结束事件(审批通过或审批拒绝)。

这个流程模型可以在支持BPMN 2.0标准的流程引擎(如Flowable、Camunda等)中执行,自动化处理员工请假申请。

4.2.2 application.properties 文件

Flowable 使用类似的配置,但需要调整一些属性。

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/flowable_oa?useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    database-platform: org.hibernate.dialect.MySQL8Dialect
  flowable:
    database-schema-update: true
    async-executor-activate: false
server:
  port: 8080

4.2.3 pom.xml 文件

将 Camunda 的依赖替换为 Flowable 的依赖。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>OAdata</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--SpringBoot依赖-->
    <parent>
        <groupId> org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.13</version>
    </parent>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- Spring Boot Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Flowable Spring Boot Starter -->
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter-process</artifactId>
            <version>6.8.0</version>
        </dependency>

        <!-- MySQL JDBC 依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- Lombok 依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

4.2.4 Config

@Configuration
public class FlowableConfig {

    @Bean
    public RepositoryService repositoryService(org.flowable.engine.ProcessEngine processEngine) {
        return processEngine.getRepositoryService();
    }

    @Bean
    public RuntimeService runtimeService(org.flowable.engine.ProcessEngine processEngine) {
        return processEngine.getRuntimeService();
    }

    @Bean
    public TaskService taskService(org.flowable.engine.ProcessEngine processEngine) {
        return processEngine.getTaskService();
    }
}

Spring配置类(@Configuration),用于定义和配置Flowable工作流引擎的核心服务 Bean。它的作用是将Flowable的RepositoryServiceRuntimeServiceTaskService暴露为Spring容器中的Bean,以便在应用程序的其他地方可以通过依赖注入(@Autowired)来使用这些服务。

1. @Configuration
  • 这个注解标记了一个类为Spring配置类。Spring容器会读取这个类中的配置信息,并创建和管理其中定义的Bean。

2. @Bean
  • 这个注解用于定义一个Bean,并将其注册到Spring容器中。每个@Bean方法返回的对象都会成为Spring容器中的一个Bean。

3. Flowable 服务 Bean
  • RepositoryService: 用于管理流程定义(如部署、删除、查询流程定义等)。

  • RuntimeService: 用于启动流程实例、触发流程执行、查询流程实例等。

  • TaskService: 用于管理用户任务(如创建、完成任务、查询任务等)。

4. 方法参数注入
  • 每个方法都接收一个ProcessEngine参数。Spring会自动将Flowable的ProcessEngine注入到方法中,因为ProcessEngine本身也是一个Spring Bean(通常由Flowable的自动配置提供)。

  • 通过ProcessEngine实例,可以获取Flowable的各个服务。

4.2.5 Controller 层

@RestController
@RequestMapping("/leave")
@RequiredArgsConstructor
public class LeaveRequestController {

    private final LeaveRequestService leaveRequestService;

    /**
     * 启动请假流程
     */
    @PostMapping("/start")
    public String startLeaveProcess(@RequestParam String employee) {
        return leaveRequestService.startLeaveProcess(employee);
    }

    /**
     * 获取待办任务
     */
    @GetMapping("/tasks")
    public List<TaskInfo> getTasks(@RequestParam String assignee) {
        return leaveRequestService.getTasks(assignee);
    }

    /**
     * 完成任务
     */
    @PostMapping("/complete")
    public String completeTask(@RequestParam String taskId, @RequestParam boolean approved) {
        leaveRequestService.completeTask(taskId, approved);
        return "Task " + taskId + " completed.";
    }
}

4.2.6 Service 层

@Service
@RequiredArgsConstructor
public class LeaveRequestService {

    private final RuntimeService runtimeService;
    private final TaskService taskService;

    /**
     * 启动请假流程
     */
    public String startLeaveProcess(String employee) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("employee", employee);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveProcess", variables);
        return processInstance.getId();
    }

    /**
     * 获取待办任务
     */
    public List<TaskInfo> getTasks(String assignee) {
        return taskService.createTaskQuery()
                .taskAssignee(assignee)
                .list()
                .stream()
                .map(task -> new TaskInfo(task.getId(), task.getName()))
                .collect(Collectors.toList());
    }

    /**
     * 完成任务
     */
    public void completeTask(String taskId, boolean approved) {
        Map<String, Object> variables = new HashMap<>();
        variables.put("approved", approved);
        taskService.complete(taskId, variables);
    }

    /**
     * 任务信息封装
     */
    @Data
    @AllArgsConstructor
    public static class TaskInfo {
        private String taskId;
        private String taskName;
    }
}
  • startLeaveProcess
  • Map<String, Object> variables = new HashMap<>();

    • 定义 流程变量,其中 employee 代表发起请假申请的员工。
  • variables.put("employee", employee);

    • 员工姓名/ID 存入变量,传递给流程实例。
  • runtimeService.startProcessInstanceByKey("leaveProcess", variables);

    • 启动 请假流程leaveProcess 是 BPMN 流程的 Key)。
    • 这个流程会根据 Flowable 设计的 BPMN 模型进行流转。
    • 启动<process id="leaveProcess" name="员工请假流程" isExecutable="true">流程
    • 流程自动转到
      <startEvent id="start" name="申请请假">
          <extensionElements>
              <flowable:initiator value="employee"/>
          </extensionElements>
      </startEvent>
    • 并将流程推进到
      <!-- 提交申请任务 -->
      <userTask id="applyTask" name="提交请假申请" flowable:assignee="${employee}"/>
  • return processInstance.getId();

    • 返回该流程实例的 ID,可以用来追踪流程状态。
  • getTasks
  • taskService.createTaskQuery()

    • 创建任务查询对象
  • .taskAssignee(assignee)

    • 查询分配给指定人的任务
  • .list()

    • 获取 任务列表
  • .stream()...map(task -> new TaskInfo(task.getId(), task.getName()))...collect(Collectors.toList());

    • 将查询到的 Task 对象转换为 TaskInfo 对象,返回任务信息(任务 ID 和名称)。
  • completeTask
  • Map<String, Object> variables = new HashMap<>();

    • 创建 变量集合,用于传递任务结果。
  • variables.put("approved", approved);

    • 审批结果(true/false) 存入流程变量。
    • true 代表审批通过,false 代表审批拒绝。
  • taskService.complete(taskId, variables);

    • 完成任务,并传递 approved 变量,流程将根据这个变量决定接下来的流转方向(如审批通过则进入下一步,否则结束流程)。

4.2.7 完整流程

完整流程示例

步骤 1:员工发起请假申请
  • 调用接口:

    POST /leave/start?employee=张三
  • 返回结果:

    "流程实例ID:12345"
步骤 2:员工提交申请
  • 员工登录系统,查看自己的任务:

    GET /leave/tasks?assignee=张三
  • 返回结果:

    [{"taskId": "67890", "taskName": "提交请假申请"}]
  • 员工完成任务:

    POST /leave/complete?taskId=67890&approved=true
步骤 3:经理审批
  • 经理登录系统,查看自己的任务:

    GET /leave/tasks?assignee=manager
  • 返回结果:

    [{"taskId": "54321", "taskName": "经理审批"}]
  • 经理完成任务:

    POST /leave/complete?taskId=54321&approved=true

猜你喜欢

转载自blog.csdn.net/weixin_51721783/article/details/146251360
今日推荐