SpringBoot + Flowable并集成ui,写一个请假流程Demo!

初识flowable工作流-实现简单请假流程SpringBoot+VUE flowable实现简单请假流程,后台使用SpringCloud分布式框架,前端使用Vue。 阅读详情

👉 这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料: 

👉这是一个或许对你有用的开源项目

国产Star破10w的开源项目,前端包括管理后台、微信小程序,后端支持单体、微服务架构

RBAC权限、数据权限、SaaS多租户、商城、支付、工作流、大屏报表、ERP、CRM、AI大模型、IoT物联网等功能:

  • 多模块:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • 微服务:https://gitee.com/zhijiantianya/yudao-cloud

  • 视频教程:https://doc.iocoder.cn

【国内首批】支持 JDK17/21+SpringBoot3、JDK8/11+Spring Boot2双版本 

来源:juejin.cn/post/

7387380647269253146


找了好多文章,每个文章多多少少都有坑点,终于是搞出来了,本文只搞整合,如需详细定义可自行去搜索,网上很多。

程序相关

环境
  • jdk1.8

  • maven3

  • SpringBoot 2.7.5

  • flowable 6.6.0

  • MySQL8

目录
依赖
<properties>
  <maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<flowable.version>6.6.0</flowable.version>
</properties>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/><!-- lookup parent from repository -->
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 工作流flowable jar包 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>${flowable.version}</version>
</dependency>
<!-- 下面俩皆是flowable-ui所需jar包,不用ui画流程图的可不加 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-ui-idm</artifactId>
<version>${flowable.version}</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-ui-modeler</artifactId>
<version>${flowable.version}</version>
</dependency>
<!-- 忘了这家伙干啥的了,好像是解决中途的某个报错的,诸位可去掉验证验证 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-bpmn-layout</artifactId>
<version>${flowable.version}</version>
</dependency>
<!-- mysql数据库连接jar包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<!-- mybatis ORM jar包 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
配置

application.properties (可自行改为yml)

#端口
server.port=8081

#ui相关信息
flowable.idm.app.admin.user-id=admin
flowable.idm.app.admin.password=admin
flowable.idm.app.admin.first-name=xxx
flowable.idm.app.admin.last-name=xxx
flowable.database-schema-update=true# 没有数据库表的时候生成数据库表(true)  建表后可关闭(false),下次启动不会再次建表

> 基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
>
> * 项目地址:<https://github.com/YunaiV/ruoyi-vue-pro>
> * 视频教程:<https://doc.iocoder.cn/video/>

# 关闭定时任务JOB
flowable.async-executor-activate=false
#数据库
spring.datasource.url=jdbc:mysql://xxxx:3306/flowable-test?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true #此处的nullCatalogMeansCurrent=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
#日志
logging.level.org.flowable=DEBUG

注意

  • &nullCatalogMeansCurrent=true 这个一定要加在url后,不然flowable自动创建表失败

  • 在数据库中创建flowable数据库,启动项目时,flowable服务会自动创建对应的表

  • 启动项目后 网站的登录用户 密码 user-id: admin password: admin

表

后面还有很多,自动创建的,我也没数过

类

防止流程图乱码FlowableConfig

package org.example.config;

import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.context.annotation.Configuration;

/**
 * flowable配置----为放置生成的流程图中中文乱码
 */
@Configuration
publicclass FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {


@Override
public void configure(SpringProcessEngineConfiguration engineConfiguration) {
    engineConfiguration.setActivityFontName("宋体");
    engineConfiguration.setLabelFontName("宋体");
    engineConfiguration.setAnnotationFontName("宋体");
  }
}

返回结果Result

package org.example.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@NoArgsConstructor
@AllArgsConstructor
publicclass Result {

privateboolean flag;
private String message;
private Object data;

public Result(boolean flag , String message){
    this.flag = flag;
    this.message = message;
  }
}

TaskVO封装审批列表查询结果

package org.example.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @ 审批列表查询结果
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
publicclass TaskVO {
private String id;
private String day;
private String name;
}

controller请假流程接口

package org.example.controller;

import lombok.extern.slf4j.Slf4j;
import org.example.vo.Result;
import org.example.vo.TaskVO;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/leave")
@Slf4j
publicclass LeaveController {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private ProcessEngine processEngine;

@PostMapping( "add/{day}/{studentUser}")
public Result sub(@PathVariable("day") Integer day , @PathVariable("studentUser") String studentUser) {
    // 学生提交请假申请
    Map<String, Object> map = new HashMap<>();
    map.put("day", day);
    map.put("studentName", studentUser);
    // stuLeave为学生请假流程xml文件中的id,即后面bpmn20.xml文件的process id="stuLeave"
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("stuLeave", map);
    log.info("流程实例ID:" + processInstance.getId());
    //完成申请任务
    Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
    taskService.complete(task.getId());
    //此处id为流程id
    returnnew Result(true,"提交成功.流程Id为:" + processInstance.getId()) ;
  }

@GetMapping("teacherList")
public Result teacherList() {
    //此处.taskCandidateGroup("a")的值“a”即是画流程图时辅导员审批节点"分配用户-候选组"中填写的值
    List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("a").list();
    List<TaskVO> taskVOList = tasks.stream().map(task -> {
      Map<String, Object> variables = taskService.getVariables(task.getId());
      returnnew TaskVO(task.getId(), variables.get("day").toString(), variables.get("studentName").toString());
    }).collect(Collectors.toList());
    log.info("任务列表:" + tasks);
    if (tasks == null || tasks.size() == 0) {
      returnnew Result(false,"没有任务");
    }
    returnnew Result(true,"获取成功",taskVOList);
  }

/**
   * 辅导员批准
   *
   * @param taskId 任务ID,非流程id
   */
@GetMapping("teacherApply/{taskId}")
public Result teacherApply(@PathVariable("taskId") String taskId) {
    List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("a").list();
    Task task = taskService.createTaskQuery().taskCandidateGroup("a").taskId(taskId).singleResult();
    if (task == null) {
      returnnew Result(false, "没有任务");
    }
    //通过审核
    HashMap<String, Object> map = new HashMap<>();
    map.put("outcome", "通过");
//        for (Task task : tasks) {
//            taskService.complete(task.getId(), map);
//        }
    taskService.complete(task.getId(), map);
    returnnew Result(true,"审批成功");
  }

/**
   * 辅导员拒绝
   * @param taskId 任务ID,非流程id
   */
@GetMapping( "teacherReject/{taskId}")
public Result teacherReject(@PathVariable("taskId") String taskId) {
    Task task1 = taskService.createTaskQuery().taskCandidateGroup("a").taskId(taskId).singleResult();
    //Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    if (task1 == null) {
      returnnew Result(false, "没有任务");
    }
    //通过审核
    HashMap<String, Object> map = new HashMap<>();
    map.put("outcome", "驳回");
    taskService.complete(task1.getId(), map);
    returnnew Result(true,"审批失败");
  }
/**
   * 院长获取审批管理列表
   */
@GetMapping("deanList")
public Result deanList() {
    //此处.taskCandidateGroup("b")的值“b”即是画流程图时辅导员审批节点"分配用户-候选组"中填写的值
    List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("b").list();
    List<TaskVO> taskVOList = tasks.stream().map(task -> {
      Map<String, Object> variables = taskService.getVariables(task.getId());
      returnnew TaskVO(task.getId(), variables.get("day").toString(), variables.get("studentName").toString());
    }).collect(Collectors.toList());
    if (tasks == null || tasks.size() == 0) {
      returnnew Result(false,"没有任务");
    }
    returnnew Result(true,"获取成功",taskVOList);
  }

/**
   * 院长批准
   * @param taskId 任务ID,非流程id
   * @return
   */
@GetMapping("deanApply/{taskId}")
public Result apply(@PathVariable("taskId") String taskId) {
    List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("b").list();
    //Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    if (tasks == null) {
      returnnew Result(false, "没有任务");
    }
    //通过审核
    HashMap<String, Object> map = new HashMap<>();
    map.put("outcome", "通过");
    for (Task task : tasks) {
      taskService.complete(task.getId(), map);
    }
    returnnew Result(true,"审批成功");
  }

/**
   * 院长拒绝
   * @param taskId 任务ID,非流程id
   * @return
   */
@GetMapping("deanReject/{taskId}")
public Result deanReject(@PathVariable("taskId") String taskId) {
//        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("b").list();
    Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    if (task == null) {
      returnnew Result(false, "没有任务");
    }
    //通过审核
    HashMap<String, Object> map = new HashMap<>();
    map.put("outcome", "驳回");
//        for (Task task : tasks) {
//            taskService.complete(task.getId(), map);
//        }
    taskService.complete(task.getId(), map);
    returnnew Result(true,"审批成功");
  }

/**
   * 再次申请
   * @param piId 流程id
   * @param day
   * @return
   */
@GetMapping("subAgain/{piId}/{day}")
public Result subAgain(@PathVariable("piId") String piId, @PathVariable("day") Integer day){
    Task task = taskService.createTaskQuery().processInstanceId(piId).singleResult();
    if(Objects.isNull(task)){
      returnnew Result(false, "没有任务");
    }
    Map<String, Object> map = new HashMap<>();
    map.put("day", day);
    taskService.complete(task.getId(), map);
    returnnew Result(true,"申请成功");
  }

/**
   * 生成流程图
   *
   * @param taskId 流程ID
   */
@GetMapping( "processDiagram/{taskId}")
public void genProcessDiagram(HttpServletResponse httpServletResponse,@PathVariable("taskId") String taskId) throws Exception {
    ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(taskId).singleResult();

    //流程走完的不显示图
    if (pi == null) {
      return;
    }
    Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
    //使用流程实例ID,查询正在执行的执行对象表,返回流程实例对象
    String InstanceId = task.getProcessInstanceId();
    List<Execution> executions = runtimeService
            .createExecutionQuery()
            .processInstanceId(InstanceId)
            .list();

    //得到正在执行的Activity的Id
    List<String> activityIds = new ArrayList<>();
    List<String> flows = new ArrayList<>();
    for (Execution exe : executions) {
      List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
      activityIds.addAll(ids);
    }

    //获取流程图
    BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
    ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
    ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
    InputStream in = diagramGenerator.generateDiagram(bpmnModel,
            "png", activityIds, flows, engconf.getActivityFontName(),
            engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(),
            1.0 ,true);
    OutputStream out = null;
    byte[] buf = newbyte[1024];
    int legth = 0;
    try {
      //此处设置resp的header诸多文章都没写,但是我不写出不来流程图,诸位可去掉试试
      httpServletResponse.setHeader("Content-Type",
              "image/png;charset=utf-8");
      out = httpServletResponse.getOutputStream();
      while ((legth = in.read(buf)) != -1) {
        out.write(buf, 0, legth);
      }
    } finally {
      if (in != null) {
        in.close();
      }
      if (out != null) {
        out.close();
      }
    }
  }
}

此时可以启动项目了,访问http://localhost:8081 用配置文件配置的账号密码登录

创建流程

简单画图操作

画请假流程

注意:每个审批元素属性中有个独占任务项,我参考的博客是改了的,但是我改不了,不过也没发现有啥问题,大家有兴趣可以去研究研究

在resources下创建processes文件夹,复制下载的"学生请假流程.bpmn20.xml"到该目录即可

<?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">
<process id="stuLeave" name="学生请假流程" isExecutable="true">
    <documentation>学校学生请假流程</documentation>
    <startEvent id="startEvent1" name="开始" flowable:formFieldValidation="true"></startEvent>
    <userTask id="apply" name="请假申请" flowable:assignee="${studentName}" flowable:formFieldValidation="true">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <userTask id="teacherPass" name="辅导员审批" flowable:candidateGroups="a" flowable:formFieldValidation="true"></userTask>
    <exclusiveGateway id="judgeTask" name="判断是否大于2天"></exclusiveGateway>
    <userTask id="principalPass" name="院长审批" flowable:candidateGroups="b" flowable:formFieldValidation="true"></userTask>
    <endEvent id="over" name="结束"></endEvent>
    <sequenceFlow id="judgeLess" name="小于2天" sourceRef="judgeTask" targetRef="over">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${day<=2}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="judgeMore" name="大于2天" sourceRef="judgeTask" targetRef="principalPass">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${day>2}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flowBeg" name="流程开始" sourceRef="startEvent1" targetRef="apply"></sequenceFlow>
    <sequenceFlow id="sid-F3C3133B-68E1-4D1B-B06B-761EDD44E9F6" name="申请流程" sourceRef="apply" targetRef="teacherPass"></sequenceFlow>
    <sequenceFlow id="TeacherNotPassFlow" name="驳回" sourceRef="teacherPass" targetRef="apply">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="teacherPassFlow" name="通过" sourceRef="teacherPass" targetRef="judgeTask">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="通过"}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="presidentNotPassFlow" name="驳回" sourceRef="principalPass" targetRef="apply">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="presidentPassFlow" name="通过" sourceRef="principalPass" targetRef="over">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
    </sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_stuLeave">
    <bpmndi:BPMNPlane bpmnElement="stuLeave" id="BPMNPlane_stuLeave">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="apply" id="BPMNShape_apply">
        <omgdc:Bounds height="80.0" width="100.0" x="209.9999968707562" y="137.99999794363978"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="teacherPass" id="BPMNShape_teacherPass">
        <omgdc:Bounds height="80.0" width="100.0" x="389.99999418854725" y="137.99999794363978"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="judgeTask" id="BPMNShape_judgeTask">
        <omgdc:Bounds height="40.0" width="40.0" x="569.9999915063382" y="157.99999764561656"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="principalPass" id="BPMNShape_principalPass">
        <omgdc:Bounds height="80.0" width="100.0" x="539.9999834597114" y="284.9999915063383"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="over" id="BPMNShape_over">
        <omgdc:Bounds height="28.0" width="28.0" x="794.9999881535771" y="163.9999975562096"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="presidentNotPassFlow" id="BPMNEdge_presidentNotPassFlow">
        <omgdi:waypoint x="539.9999834597114" y="324.9999915063383"></omgdi:waypoint>
        <omgdi:waypoint x="259.9999968707562" y="324.9999915063383"></omgdi:waypoint>
        <omgdi:waypoint x="259.9999968707562" y="217.9499979436398"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="judgeLess" id="BPMNEdge_judgeLess">
        <omgdi:waypoint x="609.4890905518624" y="178.45641965548475"></omgdi:waypoint>
        <omgdi:waypoint x="795.0000204150059" y="178.03191983331223"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-F3C3133B-68E1-4D1B-B06B-761EDD44E9F6" id="BPMNEdge_sid-F3C3133B-68E1-4D1B-B06B-761EDD44E9F6">
        <omgdi:waypoint x="309.94999687075494" y="177.99999794363978"></omgdi:waypoint>
        <omgdi:waypoint x="389.99999418854725" y="177.99999794363978"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="judgeMore" id="BPMNEdge_judgeMore">
        <omgdi:waypoint x="590.4349219597013" y="197.50836625144538"></omgdi:waypoint>
        <omgdi:waypoint x="590.1363337825771" y="284.9999915063383"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flowBeg" id="BPMNEdge_flowBeg">
        <omgdi:waypoint x="129.94999913083947" y="177.99999978727305"></omgdi:waypoint>
        <omgdi:waypoint x="209.99999373428892" y="177.99999865202045"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="presidentPassFlow" id="BPMNEdge_presidentPassFlow">
        <omgdi:waypoint x="639.9499834597113" y="324.9999915063383"></omgdi:waypoint>
        <omgdi:waypoint x="808.9999881535771" y="324.9999915063383"></omgdi:waypoint>
        <omgdi:waypoint x="808.9999881535771" y="191.94992565845044"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="TeacherNotPassFlow" id="BPMNEdge_TeacherNotPassFlow">
        <omgdi:waypoint x="439.99999418854725" y="137.99999794363978"></omgdi:waypoint>
        <omgdi:waypoint x="439.99999418854725" y="68.00000129640101"></omgdi:waypoint>
        <omgdi:waypoint x="259.9999968707562" y="68.00000129640101"></omgdi:waypoint>
        <omgdi:waypoint x="259.9999968707562" y="137.99999794363978"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="teacherPassFlow" id="BPMNEdge_teacherPassFlow">
        <omgdi:waypoint x="489.949994188544" y="178.16594469153907"></omgdi:waypoint>
        <omgdi:waypoint x="570.4333248783485" y="178.43333101762673"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

演示

提交申请

辅导员审批列表

流程图

辅导员批准

流程图

院长获取审批列表

院长拒绝

流程图

再次申请

流程图

辅导员审批列表

其它流程大家可自行验证

大家一定要注意各个接口的入参id,有的是流程id,有的是任务id,且任务id也会随着节点变动而变动,我是从审批列表中获取的,关于id变动这块,大家有兴趣可深入研究下,我反正是一脸懵,大家可以看看ACT_RU_TASK这张表观察观察每个审批节点的id变化情况

表结构

  • ACT_RE : 'RE’表示 repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。

  • ACT_RU: 'RU’表示 runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Flowable只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。

  • ACT_HI: 'HI’表示 history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。

  • ACT_GE: GE 表示 general。 通用数据, 用于不同场景下

  • ACT_ID: ’ID’表示identity(组织机构)。这些表包含标识的信息,如用户,用户组,等等。


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,“长按”或“扫描”下方二维码噢:

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
Flowable 6.7.X 学习笔记(一) 安装及请假流程的创建 阅读详情

相关推荐

JEECG/SpringBoot集成flowable流程框架

本文介绍了如何在IDEA中安装Flowable BPMN visualizer插件,并通过配置pom.xml引入Flowable相关依赖。接着,在yml文件中增加了Flowable的配置,包括异步执行、自动更新数据库和流程文件校验等。此外,项目中新增了FlowableConfig和SecurityConfiguration两个配置文件,分别用于设置流程引擎的字体和绕过Flowable的登录验证。最后,提供了一个流程控制器AskForLeaveFlowableController,用于处理员工提交请假申请的流

Counter-Strike大牛 3267

flowable-ui(v6.7.2)简单的请假流程审批操作(二)

flowable-ui工作流请假审批实例操作

michaelzhuang89的专栏 2198

springBoot集成flowable

Flowable可以十分灵活地加入你的应用/服务/构架。可以将JAR形式发布的Flowable库加入应用或服务,来嵌入引擎。以JAR形式发布使Flowable可以轻易加入任何Java环境:Java SE;Tomcat、Jetty或Spring之类的servlet容器;JBoss或WebSphere之类的Java EE服务器,等等。另外,也可以使用Flowable REST API进行HTTP调用。

ZL4120505的博客 3008

【Flowable | 第二篇】使用Flowable工作流实现请假流程

使用Flowable工作流实现请假流程

踢桃的成长之路 3031

ruoyi-vue-pro yudao(芋道) 项目bpm模块SQL脚本

ruoyi-vue-pro yudao(芋道) 项目bpm模块SQL脚本

基于RuoYi-VUE版本开发的OA协同办公系统源码 集成Flowable流程引擎

1.用户管理:用户是系统操作者,该功能主要完成系统用户配置。 2.部门管理:配置系统组织机构,树结构展现支持数据权限。 3.岗位管理:配置系统用户所属担任职务。 4.菜单管理:配置系统菜单,操作权限,按钮权限标识等。 5.角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 6.字典管理:对系统中经常使用的一些较为固定的数据进行维护。 7.参数管理:对系统动态配置常用参数。 8.通知公告:系统通知公告信息发布维护。 9.操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 10.登录日志:系统登录日志记录查询包含登录异常。 11.在线用户:当前系统中活跃用户状态监控。 12.定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 13.代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 14.系统接口:根据业务代码自动生成相关的api接口文档。 15.服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 16.缓存监控:对系统的缓存信息查询,命令统计等。 17.在线构建器:拖动表单元素生成相应的html代码

flowable-ui(v6.7.2)简单的请假流程审批操作(一)

flowable-ui v6.7.2 简单请假流程审批实例操作

michaelzhuang89的专栏 2310

全网首发:香橙派5MAX安装ubuntu20.04(换了官方桌面)及ros,运行LIVOX-mid360混合固态激光雷达,实际测试fastlio(只能说可以跑,还是有点吃力)

独家发布!!!香橙派5MAX安装ubuntu20.04(换了官方桌面)及ros,运行mid360混合固态激光雷达,测试fastlio(只能说可以跑,还是有点吃力),国货也算崛起了。

2402_82745259的博客 6001

SpringBoot + Flowable并集成ui,写一个请假流程Demo

大家一定要注意各个接口的入参id,有的是流程id,有的是任务id,且任务id也会随着节点变动而变动,我是从审批列表中获取的,关于id变动这块,大家有兴趣可深入研究下,我反正是一脸懵,大家可以看看ACT_RU_TASK这张表观察观察每个审批节点的id变化情况。这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。注意:每个审批元素属性中有个独占任务项,我参考的博客是改了的,但是我改不了,不过也没发现有啥问题,大家有兴趣可以去研究研究。这些表包含标识的信息,如用户,用户组,等等。

tangjieqing的博客 1181

C#上位机与VisionPro通用框架:视觉标定、通信联动与现场排坑实战

工业自动化设备的上位机开发,往往面临流程控制、视觉检测、通信交互等环节的重复搭建。C#作为主流工业语言,配合VisionPro视觉软件,可通过通用框架设计将状态机调度、相机采集、标定算法与串口/扫码枪通信等底层能力模块化,从而大幅降低项目交付成本。其核心原理在于:将设备工艺差异封装至配置层,视觉流程通过CogToolBlock工具链与VPP模板复用,九点标定建立像素与机械坐标系的映射关系。该方案已在螺丝锁付、点胶定位等多类产线落地,尤其适用于批量交付、换型频繁的视觉设备场景。这套从实践中沉淀的框架思路,以及

weixin_31102231的博客 340

Delphi中使用FireDAC与uniDAC高效连接PostgreSQL的实战指南

本文为Delphi开发者提供了使用FireDAC与uniDAC组件高效连接PostgreSQL数据库的实战指南。文章详细对比了两款组件的选择策略,重点解析了驱动依赖(libpq.dll)的配置、连接参数设置、常见错误排查及性能优化技巧,旨在帮助开发者快速构建稳定可靠的数据库连接。

tomato的博客 809

Spring Boot 集成 Flowable UI 实现请假流程 Demo

​博客主页:在现代企业应用中,工作流管理是一个至关重要的部分。通过使用Spring Boot和Flowable,可以方便地构建和管理工作流。本文将详细介绍如何在Spring Boot项目中集成Flowable UI,并实现一个简单的请假流程。

2301_76419561的博客 2148

【目标检测】全局上下文感知的详解

目标检测中的全局上下文感知(Global Context Awareness)​是指模型在定位和识别目标时,能够有效利用图像中全局或大范围的上下文信息(如场景语义、目标间关系、空间布局等),而不仅仅依赖局部特征。这种能力显著提升了检测的鲁棒性,尤其是在复杂场景(如遮挡、小目标、密集目标)中表现突出。

浩瀚之水的专栏 650

Spring Boot整合Flowable并集成ui,写一个请假流程demo

找了好多文章,每个文章多多少少都有坑点,终于是搞出来了,本文只搞整合,如需详细定义可自行去搜索,网上很多。

2301_78976656的博客 954

Unreal使用nDisplay制作裸眼3D(9宫格)

摘要: nDisplay是虚幻引擎的分布式实时渲染技术,可将内容同步输出到多个显示设备(如LED墙、投影仪等),构建沉浸式可视化系统。其核心功能包括:分布式渲染(支持多台设备协同处理高分辨率内容)、空间透视校正(通过追踪观众动态调整画面几何关系)以及虚拟拍摄应用。配置时需设置集群组件(Cluster、Host、Node、Viewport)定义渲染逻辑,空间组件(nDisplayScreen、ViewPoint)确定投影关系。文中以9宫格配置为例,详细演示了从工程创建到影片渲染合成的全流程,最终通过多视口合成

TxNet 609

14 Prompt 的边界:什么时候必须用 RAG 或微调

Prompt 不是万能解法。本文用“改输入、补知识、改模型”这条主线,讲清什么时候继续优化 Prompt,什么时候必须引入 RAG、工具调用或微调,帮助你避免用重技术掩盖轻问题。

老于的笔记的专栏 209
上一篇: 多租户的 4 种常用方案!
下一篇: 企业级私有化部署DeepSeek:SpringBoot深度集成与全功能UI实战(附语音/图片交互指南)
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值