SpringBoot+flowable快速实现工作流-动态选择审批领导

前言

OA系统中的工作流不仅是企业日常运营的重要组成部分,也是实现企业数字化转型、提高工作效率和执行力的重要工具。 在国内大部分的工作流系统使用Activiti框架实现。 其实flowable也可以轻松实现工作流业务。在线体验JeecgFlow

flowable简介

Flowable是一个使用Java编写的轻量级业务流程引擎。它主要用于部署BPMN 2.0流程定义(一种用于定义流程的行业XML标准),创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据等。Flowable流程引擎的特点包括灵活性和可扩展性,提供了图形化的流程设计器,可以与规则引擎集成,支持多种执行环境,并且可以轻易地加入任何Java环境。

版本信息

Flowable 6.7.2

SpringBoot 2.7.12

SpringBoot整合flowable

maven依赖

xml 复制代码
<flowable.spring-boot.version>6.7.2</flowable.spring-boot.version

<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter</artifactId>
    <version>${flowable.spring-boot.version}</version>
    <exclusions>
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </exclusion>
    </exclusions>
</dependency>

配置

yml 复制代码
flowable:
  #关闭定时任务JOB
  async-executor-activate: false
  #将databaseSchemaUpdate设置为true。当flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
  database-schema-update: true
  # 自动部署验证设置:true-开启(默认)、false-关闭
  check-process-definitions: false
  #保存历史数据级别设置为full最高级别,便于历史数据的追溯
  history-level: full

简单两步,就可以启动boot应用。初次运行时flowable会将自动执行flowable中的初始化脚本完成工作流所需要的数据表的建立,如果指定的数据库中还未创建过flowable的相关数据表的话。

流程定义

假设现在有一个请假需求,用户提交申请表单后, 直属领导进行审批操作。 可以是通过或拒绝。并且要求不同部门的人员绑定所属的领导。

申请节点,定义用户提交数据的字段

申请节点, 设置了任务完成后的监听器。用于动态设置审批领导的名称。

直属领导申请的节点属性设置。

xml内容

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
  <bpmn:process id="Process_choose_leader" name="动态审批" isExecutable="true">
    <bpmn:startEvent id="StartEvent_1">
      <bpmn:outgoing>Flow_09w75kg</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:sequenceFlow id="Flow_09w75kg" sourceRef="StartEvent_1" targetRef="Activity_1xn21s1" />
    <bpmn:userTask id="Activity_1xn21s1" name="申请" camunda:assignee="${general}">
      <bpmn:extensionElements>
        <camunda:formData>
          <camunda:formField id="days" label="请假天数" type="long" defaultValue="1" />
          <camunda:formField id="reason" label="请假理由" type="string" />
          <camunda:formField id="type" label="请假类型" type="string" />
        </camunda:formData>
        <camunda:taskListener delegateExpression="${chooseLeaderListener}" event="complete" />
      </bpmn:extensionElements>
      <bpmn:incoming>Flow_09w75kg</bpmn:incoming>
      <bpmn:outgoing>Flow_1n7z9g2</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:sequenceFlow id="Flow_1n7z9g2" sourceRef="Activity_1xn21s1" targetRef="Activity_0474tsq" />
    <bpmn:userTask id="Activity_0474tsq" name="直属领导" camunda:assignee="${leader}">
      <bpmn:extensionElements>
        <camunda:formData>
          <camunda:formField id="comment" label="评论" type="string" />
          <camunda:formField id="imageUrl" label="图片" type="string" />
        </camunda:formData>
      </bpmn:extensionElements>
      <bpmn:incoming>Flow_1n7z9g2</bpmn:incoming>
      <bpmn:outgoing>Flow_1lyuw6k</bpmn:outgoing>
    </bpmn:userTask>
    <bpmn:endEvent id="Event_10twye6">
      <bpmn:incoming>Flow_1lyuw6k</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="Flow_1lyuw6k" sourceRef="Activity_0474tsq" targetRef="Event_10twye6" />
  </bpmn:process>

</bpmn:definitions>

代码编写

开始流程

java 复制代码
@ApiOperation(value = "发起请假", notes = "提交请假的数据")
@PostMapping("start")
public Result<?> start(@RequestBody LeaveStartReq leaveStartReq) {
    log.info("start.leaveStartReq:{}", leaveStartReq);
    ValidatorUtils.validateEntity(leaveStartReq);
    //查询登陆用户
    String id = SecurityContextHolder.getContext().getAuthentication().getName();
    User loginUser = userService.getById(id);
    //发起流程并初始化各个用户任务节点的指定人
    Authentication.setAuthenticatedUserId(Optional.ofNullable(loginUser).map(m -> m.getUsername()).orElse("xxx"));
    Map<String, Object> variables = new HashMap<>(4);
    variables.put("general", Optional.ofNullable(loginUser).map(m -> m.getUsername()).orElse("mark"));
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(FlowConstant.MODEL_KEY_LEAVE, variables);
    //执行一个申请节点的动作
    userTaskService.completeApplyUserTask(processInstance.getId(), loginUser, leaveStartReq);
    return Results.newSuccessResult(processInstance.getId());
}

以上逻辑就是发起流程, 核心步骤就是获取登陆用户信息,并且设置流程启动参数。 在流程启动后完成第一个用户任务节点。此时流程便可以往下面流转。

完成申请任务的监听事件

java 复制代码
@Component("chooseLeaderListener")
@Slf4j
public class ChooseLeaderListener implements TaskListener {

    @Autowired
    private ISysBaseAPI sysBaseAPI;

    @Override
    public void notify(DelegateTask delegateTask) {
        log.info("动态选择下一个用户任务节点审批人员监听器");
        //查询发起用户所属的部门Id集合
        String startUser = String.valueOf(delegateTask.getVariable("general"));
        List<String> myDeptIds = sysBaseAPI.getDepartIdsByUsername(startUser);
        //根据部门id查询负责人
        List<String> leaderList = new ArrayList<>();
        for (String myDeptId : myDeptIds) {
            leaderList.addAll(sysBaseAPI.getDeptHeadByDepId(myDeptId));
        }
        log.info("直属部门领导人员:{}", leaderList);
        //设置下一个审批节点的用户名称,注意如何是有多个领导需要同时审批,要把审批节点设置为多实例。
        if(CollectionUtil.isNotEmpty(leaderList)){
            delegateTask.setVariable("leader", leaderList.get(0));
        }
    }
}

在上一步申请节点完成后,将执行任务监听起逻辑,查询到下一个节点的审批用户名称。并且绑定到leader流程变量。此时便可以实现不同部门有不同领导。

审批通过

java 复制代码
public void pass(PassReq passReq, User loginUser) {
    Task task = taskService.createTaskQuery().processInstanceId(passReq.getProcessInstanceId()).taskAssignee(loginUser.getUsername()).singleResult();
  
    //完成用户任务
    Map<String, Object> map = new HashMap<>(12);
    map.put("comment", passReq.getContent());
    map.put("imageUrl", imageUrl);
    taskService.complete(task.getId(), map);
}

审批通过操作的核心逻辑。 驳回就留给大家自己研究了。

运行效果的图

通过Springboot+flowable就是这么简单, 在线体验JeecgFlow

相关推荐
开心工作室_kaic1 分钟前
springboot337校园失物招领系统pf(论文+源码)_kaic
java·前端·spring boot·后端
脑袋凉凉3 分钟前
Django框架--中间件
后端·python·中间件·django·sqlite
用户6757049885022 小时前
hyperf-throttle-requests,一个超牛的 PHP 限流神器
后端·php
考虑考虑3 小时前
JDK8加载拓展包
java·后端·java ee
追逐时光者3 小时前
一款.NET开源的Windows资源管理器标签页工具
windows·后端·.net
waterme1onY4 小时前
由于导包而引发的错误
java·开发语言·笔记·后端
程序员清风4 小时前
RocketMQ负载均衡机制解析!
java·后端·面试
mit6.8244 小时前
[Redis#6] list | 命令 | 应用 | 消息队列 | 微博 Timeline
linux·redis·后端·云原生·架构
jeikerxiao5 小时前
Ubuntu24.04 安装 Docker
后端