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

faa7385c85d8e9e0068c0ee90b0e97cc.jpeg来源:juejin.cn/post/7387380647269253146

👉 欢迎加入小哈的星球,你将获得: 专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17..., 点击查看项目介绍

  • 《从零手撸:前后端分离博客项目(全栈开发)》 2期已完结,演示链接:http://116.62.199.48/;

截止目前,累计输出 54w+ 字,讲解图 2330+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,Spring Cloud Alibaba 等等,戳我加入学习,解锁全部项目,已有2000+小伙伴加入

1798237cbd77f8c6fc4718507d4050b9.gif

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

程序相关

环境
  • jdk1.8

  • maven3

  • SpringBoot 2.7.5

  • flowable 6.6.0

  • MySQL8

目录
72d0e29d374d6129e09b505b3728c506.jpeg
图片
依赖
<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),下次启动不会再次建表
# 关闭定时任务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

a150f671903f22be4ba925d91ddee613.jpeg
图片

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

防止流程图乱码FlowableConfig

package org.example.config;

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

/**
 * flowable配置----为放置生成的流程图中中文乱码
 */
@Configuration
public class 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
public class Result {

    private boolean 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
public class 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
public class 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
        return new 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());
            return new TaskVO(task.getId(), variables.get("day").toString(), variables.get("studentName").toString());
        }).collect(Collectors.toList());
        log.info("任务列表:" + tasks);
        if (tasks == null || tasks.size() == 0) {
            return new Result(false,"没有任务");
        }
        return new 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) {
            return new 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);
        return new 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) {
            return new Result(false, "没有任务");
        }
        //通过审核
        HashMap<String, Object> map = new HashMap<>();
        map.put("outcome", "驳回");
        taskService.complete(task1.getId(), map);
        return new 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());
            return new TaskVO(task.getId(), variables.get("day").toString(), variables.get("studentName").toString());
        }).collect(Collectors.toList());
        if (tasks == null || tasks.size() == 0) {
            return new Result(false,"没有任务");
        }
        return new 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) {
            return new Result(false, "没有任务");
        }
        //通过审核
        HashMap<String, Object> map = new HashMap<>();
        map.put("outcome", "通过");
        for (Task task : tasks) {
            taskService.complete(task.getId(), map);
        }
        return new 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) {
            return new 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);
        return new 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)){
            return new Result(false, "没有任务");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("day", day);
        taskService.complete(task.getId(), map);
        return new 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 = new byte[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 用配置文件配置的账号密码登录

5f996bb194e9ad08d512b400789d61d7.jpeg
图片

创建流程

8f85e87d9454c96aff2f7545d63f2f0a.jpeg
图片
9a8b71682db033fa123018aba8175e36.jpeg
图片

简单画图操作

25d8dcd6eb10f3cafc9420cda8045691.jpeg
图片

画请假流程

e0c48d355c512de85868f76bd4bb597c.jpeg
图片
9ce2b330a8225db24ea63eae02601321.jpeg
图片
503cf7e2133ea3a1051a2b1c71dcbdfc.jpeg
图片
acfb76103d59b27fe83507aa34391a1d.jpeg
图片
66be98607a7f03d0e7cf07669d547939.jpeg
图片
3f6eff78aa60e973bffca4e89913e851.jpeg
图片
e9534f1107665a4fa4d23d0e34ffadb4.jpeg
图片
1f213a0ace20928755f4617c18b0dca3.jpeg
图片
048445492413d123e38ec5148d4265d9.jpeg
图片

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

f09b744b76eda3be83500838e2be8a4c.jpeg
图片

在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>

演示

提交申请

5fb1a6bde1a2c7e436859cb5195620d2.jpeg
图片

辅导员审批列表

af6b866ca726089aee3877a993ed652b.jpeg
图片

流程图

4db272a7c1f1d04c7e5131d55dc46d72.jpeg
图片

辅导员批准

c07a528f2c379311d86f48fd57957fdf.jpeg
图片

流程图

0cf207905402b61e63594e86bce70789.jpeg
图片

院长获取审批列表

699b3a2e33891146630fa6a58c88502e.jpeg
图片

院长拒绝

798a9a64a8b44a2b5f8ae0f24170a5b1.jpeg
图片

流程图

3b820fbdf6ef5216111524ef2d2d4338.jpeg
图片

再次申请

1ce9122d674c344057d6ce8059a5860c.jpeg
图片

流程图

51fa25909b06b4105de581578ae8a40e.jpeg
图片

辅导员审批列表

3d9334e90c09669783c37e5060f6d06a.jpeg
图片

其它流程大家可自行验证

大家一定要注意各个接口的入参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(组织机构)。这些表包含标识的信息,如用户,用户组,等等。

👉 欢迎加入小哈的星球,你将获得: 专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17..., 点击查看项目介绍

  • 《从零手撸:前后端分离博客项目(全栈开发)》 2期已完结,演示链接:http://116.62.199.48/;

截止目前,累计输出 54w+ 字,讲解图 2330+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,Spring Cloud Alibaba 等等,戳我加入学习,解锁全部项目,已有2000+小伙伴加入

c6dc82e15b49a9854d8f9302f090833f.gif

f063077837b5c606535aed5a234ca712.jpeg

 
 

bb8f1dff1946c24182a44eb89444ebaf.gif

 
 
 
 
1. 我的私密学习小圈子~
2. 终极 Nginx 配置指南(全网最详细)
3. 线程池不再乱配线程数了
4. SpringBoot 物理线程、虚拟线程、Webflux 性能全面对比!
 
 
最近面试BAT,整理一份面试资料《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。
PS:因公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。
点“在看”支持小哈呀,谢谢啦
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Boot一个基于Spring框架的快速开发框架,可以帮助开发者快速搭建基于Spring的应用程序。Flowable一个流程引擎,可以帮助开发者快速实现业务流程的自动化管理。Spring BootFlowable的结合可以让开发者更加方便地实现业务流程的自动化管理,提高开发效率和业务效率。 ### 回答2: SpringBoot Flowable是一款基于SpringBootFlowable和RESTful风格的Web应用程序开发框架。SpringBoot框架是一个独立的、基于Spring框架的应用程序开发框架,它简化了Spring应用程序的配置和部署,并提供快速的开发、测试和部署功能。Flowable框架是基于BPMN2.0标准的一个开源的流程引擎框架,它提供了丰富的流程定义、任务管理、历史记录、事件跟踪等功能,便于企业进行复杂业务流程的管理和优化。 SpringBoot Flowable框架的主要特点包括: 1.高效简便:SpringBoot Flowable采用SpringBoot框架简化了Spring应用程序的配置和部署,同时结合Flowable框架,使流程定义和任务管理更加简便高效。 2.易于扩展:SpringBoot Flowable框架采用RESTful风格的接口设计,与其它系统集成更加简单方便,同时也支持二次开发和自定义扩展。 3.丰富的功能:SpringBoot Flowable框架集成Flowable框架所提供的全部功能,包括流程定义、任务管理、历史记录、事件跟踪等,支持企业复杂业务流程的管理和优化。 4.支持多平台:SpringBoot Flowable框架可以部署在不同系统平台上,如Windows、Linux等,实现跨平台共享和应用。 在使用SpringBoot Flowable框架的过程中,需要掌握SpringBoot框架和Flowable框架的相关知识,同时注意提升系统的安全性和稳定性。可以参考SpringBootFlowable的官方文档进行学习和参考,也可以借助其它资料和开发者社区进行交流和分享。 ### 回答3: Spring Boot一个开源的Java开发框架,可以快速地开发基于Java的Web应用程序。它提供了许多内置的功能和自动配置,使开发者能够轻松地构建可扩展的、高度可用的应用程序。而Flowable一个开源的工作流引擎,它基于BPMN(Business Process Model and Notation)标准,可以帮助企业完成复杂的业务流程,实现业务可视化、自动化流转和智能化控制。 Spring BootFlowable的结合使得开发者能够轻松地使用Flowable来构建业务流程。使用Spring BootFlowable代码可以快速地实现流程引擎的集成和管理,同时也方便了开发人员使用Spring Boot框架进行Web开发。 Spring Boot可以使用简便的方式来配置Flowable,使用它提供的自动配置和starter等模块来进行流程引擎的集成和管理。同时,Spring Boot还提供了丰富的开发工具和插件,使得开发者能够轻松地进行代码调试和测试。 在使用Spring BootFlowable进行业务流程开发时,开发者可以使用Flowable提供的任务列表、流程修改等功能,可以轻松地修改业务流程,使得业务流程变得更加智能化和高效化。同时,Spring BootFlowable的结合也使得业务流程的开发变得更加简单和可靠。 总之,Spring BootFlowable的结合可以使开发者轻松地构建高可用、高效率、智能化的业务流程,并且简化了开发和管理流程引擎的过程,帮助企业实现业务的自动化和智能化管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值