SpringBoot集成Flowable工作流

文章目录

  • 一、了解Flowable
    • 1. 什么是Flowable
    • 2. Flowable基本流程
    • 3. Flowable主要几张表介绍
  • 二、SpringBoot集成Flowable
    • 1. 在idea中安装Flowable插件
    • 2. SpringBoot集成Flowable
    • 3. SpringBoot集成Flowable前端页面
  • 三、创建流程模版(以请假为例)


提示:以下是本篇文章正文内容,下面案例可供参考

一、了解Flowable

1. 什么是Flowable

Flowable下载
Flowable源码GitHub下载
Flowable用户使用手册
Flowable是一个使用Java编写的轻量级业务流程引擎。Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标准), 创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据,等等。

具体介绍请看Flowable介绍

2. Flowable基本流程

参考知乎Flowable工作流引擎

对于业务建模,我们需要一种通用的语言来描绘,这样在沟通上和实现上会降低难度,就像中文、英文一样,BPMN2.0便是一种国际通用的建模语言,他能让自然人轻松阅读,更能被计算机所解析。
协议中元素的主要分类为,事件-任务-连线-网关
一个流程必须包含一个事件(如:开始事件)和至少一个结束(事件)。其中网关的作用是流程流转逻辑的控制。任务则分很多类型,他们各司其职,所有节点均由连线联系起来。
BPMN2.0协议
在这里插入图片描述
不同的图标代表不同的含义

  1. 网关
    在这里插入图片描述

互斥网关(Exclusive Gateway) 又称排他网关,他有且仅有一个有效出口,可以理解为if…else if… else if…else,就和我们平时写代码的一样。
在这里插入图片描述

并行网关(Parallel Gateway) 他的所有出口都会被执行,可以理解为开多线程同时执行多个任务。
在这里插入图片描述

包容性网关(Inclusive Gateway)
只要满足条件的出口都会执行,可以理解为 if(…) do, if (…) do, if (…)
do,所有的条件判断都是同级别的。
在这里插入图片描述

  1. 任务
    在这里插入图片描述

人工任务(User Task)
它是使用得做多的一种任务类型,他自带有一些人工任务的变量,例如签收人(Assignee),签收人就代表该任务交由谁处理,我们也可以通过某个特定或一系列特定的签收人来查找待办任务。利用上面的行为解释便是,当到达User
Task节点的时候,节点设置Assignee变量或等待设置Assignee变量,当任务被完成的时候,我们使用Trigger来要求流程引擎退出该任务,继续流转。
在这里插入图片描述

服务任务(Service Task)
该任务会在到达的时候执行一段自动的逻辑并自动流转。从“到达自动执行一段逻辑”这里我们就可以发现,服务任务的想象空间就可以非常大,我们可以执行一段计算,执行发送邮件,执行RPC调用,而使用最广泛的则为HTTP调用,因为HTTP是使用最广泛的协议之一,它可以解决大部分第三方调用问题,在我们的使用中,HTTP服务任务也被我们单独剥离出来作为一个特殊任务节点。
在这里插入图片描述

接受任务(Receive Task) 该任务的名字让人费解,但它又是最简单的一种任务,当该任务到达的时候,它不做任何逻辑,而是被动地等待Trigger,它的适用场景往往是一些不明确的阻塞,比如:一个复杂的计算需要等待很多条件,这些条件是需要人为来判断是否可以执行,而不是直接执行,这个时候,工作人员如果判断可以继续了,那么就Trigger一下使其流转。
在这里插入图片描述

  1. 结构
    在这里插入图片描述

调用活动(Call Activity)
调用活动可以理解为函数调用,它会引用另外一个流程使之作为子流程运行,调用活动跟函数调用的功能一样,使流程模块化,增加复用的可能性。
在这里插入图片描述

3. Flowable主要几张表介绍

Flowable在项目启动的时候会自动创建表,以下是主要几张表介绍

  • ACT_RU_TASK: 每次启动的流程都会再这张表中,表示代办项, 流程结束会删除该流程数据
  • ACT_RU_EXECUTION: 流程执行过程表, 会存该流程正在执行的过程数据, 流程结束会删除该流程数据
  • ACT_RU_VARIABLE: 流程变量表, 流程中传的参数都会再该表存储, 流程结束会删除该流程数据
  • ACT_HI_PROCINST: 历史运行流程, 当流程处理完了, 在ACT_RU_* 表中就不会有数据, 可以在该表中查询历史
  • ACT_HI_TASKINST: 历史运行的task信息,
  • ACT_RE_PROCDEF: 流程模板记录,同一个key多次发布version_字段会递增
  • ACT_RE_DEPLOYMENT: 部署的流程模板, 可以启动流程使用的

二、SpringBoot集成Flowable

1. 在idea中安装Flowable插件

File-->settings 搜索:flowable
在这里插入图片描述
安装完成,重启idea
在这里插入图片描述

2. SpringBoot集成Flowable

  1. 添加依赖
     	/*** 引入数据库依赖,Flowable在项目启动的时候会自动创建表*/<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency>/*** lombok*/<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.16</version><scope>compile</scope></dependency>/*** 添加flowable工作流依赖*/<dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version></dependency>/*** 添加flowable工作流前端页面依赖,如果项目没有集成页面,无需添加此依赖*/<dependency><groupId>org.flowable</groupId><artifactId>flowable-ui-modeler-rest</artifactId><version>6.7.2</version></dependency>/*** 添加flowable-ui-modeler配置依赖项*/<dependency><groupId>org.flowable</groupId><artifactId>flowable-ui-modeler-conf</artifactId><version>6.7.2</version></dependency>
  1. 设置application.yml
server:port: 8080  #tomcat端口servlet:context-path: /
spring:#数据库链接配置datasource:url: jdbc:mysql://127.0.0.1:3306/flowable?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: rootflowable:#异步执行async-executor-activate: true#自动更新数据库database-schema-update: true#校验流程文件,默认校验resources下的processes文件夹里的流程文件process-definition-location-prefix: classpath*:/processes/process-definition-location-suffixes: "**.bpmn20.xml, **.bpmn"#该配置只是防止页面报错,没有实际意义common:app:idm-admin:password: testuser: test#没有实际意义idm-url: http://localhost:8080/flowable-demo
  1. 创建 【*.bpmn20.xml】
    通过【application.yml】可知,需要在resources下的processes文件夹里的创建流程文件
    这是ask_for_leave.bpmn20.xml我自己的流程文件
    在这里插入图片描述
    ask_for_leave.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="askForLeave" name="ask_for_leave_process" isExecutable="true"><startEvent id="sid-b3fcb298-124a-4dc3-b603-1397b392e1a5"/><userTask id="employee" name="员工" flowable:assignee="#{employeeNo}" flowable:formFieldValidation="true"><documentation>员工提交申请</documentation></userTask><sequenceFlow id="sid-9a4f7da0-7df8-422c-8d93-fcfe6eed6454" sourceRef="sid-b3fcb298-124a-4dc3-b603-1397b392e1a5" targetRef="employee"/><userTask id="leader" name="领导" flowable:assignee="#{leaderNo}" flowable:formFieldValidation="true"/><sequenceFlow id="sid-cda53600-1fdd-4556-b1f4-434cdef4b44c" sourceRef="employee" targetRef="leader"/><exclusiveGateway id="sid-53b678ee-c126-46be-9bb7-70efe235451c"/><sequenceFlow id="sid-c18a730f-6932-4036-b105-a840204bbd1f" sourceRef="leader" targetRef="sid-53b678ee-c126-46be-9bb7-70efe235451c"/><endEvent id="sid-dc057597-34a0-4835-bbbb-1b12f0e8e407"/><sequenceFlow id="leaderExamine" sourceRef="sid-53b678ee-c126-46be-9bb7-70efe235451c" targetRef="sid-dc057597-34a0-4835-bbbb-1b12f0e8e407" name="领导审核不通过"><conditionExpression xsi:type="tFormalExpression">${outcome=='驳回'}</conditionExpression></sequenceFlow><userTask id="boss" name="老板" flowable:formFieldValidation="true" flowable:assignee="#{bossNo}"/><sequenceFlow id="leaderExaminePass" sourceRef="sid-53b678ee-c126-46be-9bb7-70efe235451c" targetRef="boss" name="领导审核通过"><conditionExpression xsi:type="tFormalExpression">${outcome=='通过'}</conditionExpression></sequenceFlow><exclusiveGateway id="sid-17d3919b-99f0-4a2e-8914-3dfb7bc74046"/><sequenceFlow id="sid-e4dd8e02-acc7-4e51-95d4-5a1ade5eb2fd" sourceRef="boss" targetRef="sid-17d3919b-99f0-4a2e-8914-3dfb7bc74046"/><endEvent id="sid-311b83fa-5c04-48af-8491-4e2f9417c49c"/><sequenceFlow id="bossExamine" sourceRef="sid-17d3919b-99f0-4a2e-8914-3dfb7bc74046" targetRef="sid-311b83fa-5c04-48af-8491-4e2f9417c49c" name="老板审核不通过"><conditionExpression xsi:type="tFormalExpression">${outcome=='驳回'}</conditionExpression></sequenceFlow><endEvent id="sid-3f6150ad-4b8c-47e9-a726-39f5dffd5e0a"/><sequenceFlow id="bossExaminePass" sourceRef="sid-17d3919b-99f0-4a2e-8914-3dfb7bc74046" targetRef="sid-3f6150ad-4b8c-47e9-a726-39f5dffd5e0a" name="老板审核通过"><conditionExpression xsi:type="tFormalExpression">${outcome=='通过'}</conditionExpression></sequenceFlow></process><bpmndi:BPMNDiagram id="BPMNDiagram_ask_for_leave"><bpmndi:BPMNPlane bpmnElement="askForLeave" id="BPMNPlane_ask_for_leave"><bpmndi:BPMNShape id="shape-c5da47a1-57a1-465c-a7f8-2aad63d19b47" bpmnElement="sid-b3fcb298-124a-4dc3-b603-1397b392e1a5"><omgdc:Bounds x="-203.0" y="-10.75" width="30.0" height="30.0"/></bpmndi:BPMNShape><bpmndi:BPMNShape id="shape-71f351aa-e8f4-4656-9fa0-7979ddc1d916" bpmnElement="employee"><omgdc:Bounds x="-140.0" y="-10.5" width="61.0" height="29.5"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-a0cd4bce-af0a-40ce-8128-97629a5f4a23" bpmnElement="sid-9a4f7da0-7df8-422c-8d93-fcfe6eed6454"><omgdi:waypoint x="-173.0" y="4.25"/><omgdi:waypoint x="-140.0" y="4.25"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="shape-6a814a53-e6e2-4453-bb4a-43a1167e5559" bpmnElement="leader"><omgdc:Bounds x="-46.5" y="-11.0" width="63.0" height="30.5"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-3a2944ef-43d6-4409-920d-9d3d1acd422f" bpmnElement="sid-cda53600-1fdd-4556-b1f4-434cdef4b44c"><omgdi:waypoint x="-79.0" y="4.25"/><omgdi:waypoint x="-46.5" y="4.25"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="shape-bef28649-6416-4428-a3bd-43edb5c1b9c6" bpmnElement="sid-53b678ee-c126-46be-9bb7-70efe235451c"><omgdc:Bounds x="42.36" y="-15.75" width="40.0" height="40.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-fa69c266-5b3c-4e26-a4e2-3f58c271ebb4" bpmnElement="sid-c18a730f-6932-4036-b105-a840204bbd1f"><omgdi:waypoint x="16.5" y="4.25"/><omgdi:waypoint x="42.36" y="4.25"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="shape-9d577a21-ca61-4e33-bf3e-c892557f1638" bpmnElement="sid-dc057597-34a0-4835-bbbb-1b12f0e8e407"><omgdc:Bounds x="47.36" y="54.97" width="30.0" height="30.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-5651dbf2-4118-4668-bbd6-0259282cc084" bpmnElement="leaderExamine"><omgdi:waypoint x="62.36" y="24.25"/><omgdi:waypoint x="62.36" y="54.97"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="shape-1398abfb-fefc-4a16-881c-84a6c4b7b7f7" bpmnElement="boss"><omgdc:Bounds x="108.86" y="-12.75" width="68.0" height="34.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-3f5df081-8086-492f-a2c7-90aba1c1e4d7" bpmnElement="leaderExaminePass"><omgdi:waypoint x="82.36" y="4.25"/><omgdi:waypoint x="108.86" y="4.25"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="shape-4932221b-736b-4e85-a319-0859dbeb3e6b" bpmnElement="sid-17d3919b-99f0-4a2e-8914-3dfb7bc74046"><omgdc:Bounds x="203.35999" y="-15.75" width="40.0" height="40.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-3daa1ef4-119f-4b98-a40e-0b9cb3b205ce" bpmnElement="sid-e4dd8e02-acc7-4e51-95d4-5a1ade5eb2fd"><omgdi:waypoint x="176.86" y="4.25"/><omgdi:waypoint x="203.35999" y="4.25"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="shape-6becf929-e7e7-4153-a1d1-6175677742ca" bpmnElement="sid-311b83fa-5c04-48af-8491-4e2f9417c49c"><omgdc:Bounds x="208.35999" y="54.97" width="30.0" height="30.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-1f1a1414-f4f9-442a-97af-676878899415" bpmnElement="bossExamine"><omgdi:waypoint x="223.35999" y="24.25"/><omgdi:waypoint x="223.35999" y="54.97"/></bpmndi:BPMNEdge><bpmndi:BPMNShape id="shape-919e70dd-5004-4066-8103-427901b5c1fd" bpmnElement="sid-3f6150ad-4b8c-47e9-a726-39f5dffd5e0a"><omgdc:Bounds x="275.86" y="-10.75" width="30.0" height="30.0"/></bpmndi:BPMNShape><bpmndi:BPMNEdge id="edge-542631d7-42d7-4b2a-b467-da8fdba298a1" bpmnElement="bossExaminePass"><omgdi:waypoint x="243.35999" y="4.25"/><omgdi:waypoint x="275.86" y="4.25"/></bpmndi:BPMNEdge></bpmndi:BPMNPlane></bpmndi:BPMNDiagram>
</definitions>
  1. 设置配置文件
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.context.annotation.Configuration;@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {/*** 防止生成的流程图中文乱码* @param springProcessEngineConfiguration*/@Overridepublic void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) {springProcessEngineConfiguration.setActivityFontName("宋体");springProcessEngineConfiguration.setLabelFontName("宋体");springProcessEngineConfiguration.setAnnotationFontName("宋体");}
}

如果醒目没有集成页面,【SecurityConfiguration.java】无需配置
参考简书springboot集成flowable

import org.flowable.ui.common.security.SecurityConstants;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;/*** 绕过flowable的登录验证*/
@Configuration
public class SecurityConfiguration {@Configuration(proxyBeanMethods = false)//Order配置说明// 这个地方相同会报错//这个地方如果大于则该配置在FlowableUiSecurityAutoConfiguratio中对应项后加载,不能起到绕过授权作用//所以这个地方-1让该配置项在FlowableUiSecurityAutoConfiguratio中对应配置项前加载,以跳过授权@Order(SecurityConstants.FORM_LOGIN_SECURITY_ORDER - 1)public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.headers().frameOptions().disable();http//必须要将csrf设置为disable,不然后面发送POST请求时会报403错误.csrf().disable()//为了简单起见,简单粗暴方式直接放行modeler下面所有请求.authorizeRequests().antMatchers("/modeler/**").permitAll();}}
}
  1. 书写逻辑
import lombok.extern.slf4j.Slf4j;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;@Slf4j
@RestController
@RequestMapping("askForLeave")
public class AskForLeaveFlowableController {@Autowiredprivate RuntimeService runtimeService;@Autowiredprivate TaskService taskService;@Autowiredprivate RepositoryService repositoryService;@Autowiredprivate ProcessEngine processEngine;/*** 员工提交请假申请** @param employeeNo 员工工号* @param name       姓名* @param reason     原因* @param days       天数* @return*/@GetMapping("employeeSubmit")public String employeeSubmitAskForLeave(@RequestParam(value = "employeeNo") String employeeNo,@RequestParam(value = "name") String name,@RequestParam(value = "reason") String reason,@RequestParam(value = "days") Integer days) {HashMap<String, Object> map = new HashMap<>();/*** 员工编号字段来自于配置文件*/map.put("employeeNo", employeeNo);map.put("name", name);map.put("reason", reason);map.put("days", days);/***      key:配置文件中的下个处理流程id*      value:默认领导工号为002*/map.put("leaderNo", "002");/*** askForLeave:为开启流程的id  与配置文件中的一致*/ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("askForLeave", map);log.info("{},提交请假申请,流程id:{}", name, processInstance.getId());return "提交成功,流程id:"+processInstance.getId();}/*** 领导审核通过* @param employeeNo  员工工号* @return*/@GetMapping("leaderExaminePass")public String leaderExamine(@RequestParam(value = "employeeNo") String employeeNo) {List<Task> taskList = taskService.createTaskQuery().taskAssignee(employeeNo).orderByTaskId().desc().list();if (null == taskList) {throw  new RuntimeException("当前员工没有任何申请");}for (Task task : taskList) {if (task == null) {log.info("任务不存在 ID:{};", task.getId());continue;}log.info("任务 ID:{};任务处理人:{};任务是否挂起:{}", task.getId(), task.getAssignee(), task.isSuspended());Map<String, Object> map = new HashMap<>();/***      key:配置文件中的下个处理流程id*      value:默认老板工号为001*/map.put("bossNo", "001");/***      key:指定配置文件中的条件判断id*      value:指定配置文件中的审核条件*/map.put("outcome", "通过");taskService.complete(task.getId(), map);}return "领导审核通过";}/*** 老板审核通过* @param leaderNo  领导工号* @return*/@GetMapping("bossExaminePass")public String bossExamine(@RequestParam(value = "leaderNo") String leaderNo) {List<Task> taskList = taskService.createTaskQuery().taskAssignee(leaderNo).orderByTaskId().desc().list();if (null == taskList) {throw  new RuntimeException("当前员工没有任何申请");}for (Task task : taskList) {if (task == null) {log.info("任务不存在 ID:{};", task.getId());continue;}log.info("任务 ID:{};任务处理人:{};任务是否挂起:{}", task.getId(), task.getAssignee(), task.isSuspended());Map<String, Object> map = new HashMap<>();/***     老板是最后的审批人   无需指定下个流程*/
//            map.put("boss", "001");/***      key:指定配置文件中的条件判断id*      value:指定配置文件中的审核条件*/map.put("outcome", "通过");taskService.complete(task.getId(), map);}return "领导审核通过";}/*** 驳回** @param employeeNo  员工工号* @return*/@GetMapping("reject")public String reject(@RequestParam(value = "employeeNo") String employeeNo) {List<Task> taskList = taskService.createTaskQuery().taskAssignee(employeeNo).orderByTaskId().desc().list();if (null == taskList) {throw  new RuntimeException("当前员工没有任何申请");}for (Task task : taskList) {if (task == null) {log.info("任务不存在 ID:{};", task.getId());continue;}log.info("任务 ID:{};任务处理人:{};任务是否挂起:{}", task.getId(), task.getAssignee(), task.isSuspended());Map<String, Object> map = new HashMap<>();/***      key:指定配置文件中的领导id*      value:指定配置文件中的审核条件*/map.put("outcome", "驳回");taskService.complete(task.getId(), map);}return "申请被驳回";}/*** 生成流程图** @param processId 任务ID*/@GetMapping(value = "processDiagram")public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).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的IdList<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 {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();}}}
}
  1. 测试
  • 员工提交请假申请,如下图:
    http://localhost:8080/askForLeave/employeeSubmit?name=Jerry&reason=去旅游&days=30&employeeNo=006
    在这里插入图片描述

  • 查看员工提交申请的流程图
    http://localhost:8080/askForLeave/processDiagram?processId=2cd67ca3-c32e-11ee-a344-d41b812ff10e
    在这里插入图片描述

  • 领导进行审批
    http://localhost:8080/askForLeave/leaderExaminePass?employeeNo=006
    在这里插入图片描述

  • 查看领导审批后的流程图
    http://localhost:8080/askForLeave/processDiagram?processId=2cd67ca3-c32e-11ee-a344-d41b812ff10e
    在这里插入图片描述

  • 老板审批
    http://localhost:8080/askForLeave/bossExaminePass?leaderNo=002
    在这里插入图片描述

  • 查看老板审批后的流程图
    http://localhost:8080/askForLeave/processDiagram?processId=2cd67ca3-c32e-11ee-a344-d41b812ff10e
    在这里插入图片描述

3. SpringBoot集成Flowable前端页面

参考简书毛于晏

  1. 下载源码包,此处使用的是6.7.2版本的
    源码下载地址: https://github.com/flowable/flowable-engine/tree/flowable-6.7.2

    链接:https://pan.baidu.com/s/1w-iuynskMuREBlYcpbDFAg
    提取码:9gs7

  2. 将以下路径的代码复制到自己工程
    /flowable-6.7.2/modules/flowable-ui/flowable-ui-modeler-frontend/src/main/resources/static/modeler
    在这里插入图片描述

  3. 跳过验证

import org.flowable.ui.common.security.SecurityConstants;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;/*** 绕过flowable的登录验证*/
@Configuration
public class SecurityConfiguration {@Configuration(proxyBeanMethods = false)//Order配置说明// 这个地方相同会报错//这个地方如果大于则该配置在FlowableUiSecurityAutoConfiguratio中对应项后加载,不能起到绕过授权作用//所以这个地方-1让该配置项在FlowableUiSecurityAutoConfiguratio中对应配置项前加载,以跳过授权@Order(SecurityConstants.FORM_LOGIN_SECURITY_ORDER - 1)public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.headers().frameOptions().disable();http//必须要将csrf设置为disable,不然后面发送POST请求时会报403错误.csrf().disable()//为了简单起见,简单粗暴方式直接放行modeler下面所有请求.authorizeRequests().antMatchers("/modeler/**").permitAll();}}
}
  1. 启动项目,访问:http://localhost:8080/modeler/#/processes
    在这里插入图片描述

三、创建流程模版(以请假为例)

  1. 确保已在idea中安装Flowable插件

  2. 在resources下创建processes文件夹,右键,创建一个【*.bpmn20.xml】文件
    在这里插入图片描述

  3. 选中创建好的【*.bpmn20.xml】文件,右键;在这里插入图片描述

  4. 开始画流程图 任意位置右键–>启动一个流程
    在这里插入图片描述
    在这里插入图片描述

  5. 设置员工提交申请
    在这里插入图片描述
    在这里插入图片描述

  6. 设置领导
    在这里插入图片描述

  7. 设置网关,用来判断领导是否同意
    在这里插入图片描述
    在这里插入图片描述

  8. 网关条件判断条件–驳回
    在这里插入图片描述

  9. 网关条件判断条件–通过
    在这里插入图片描述

  10. 设置老板
    在这里插入图片描述

  11. 设置网关,用来判断老板是否同意
    在这里插入图片描述

  12. 网关条件判断条件–驳回
    在这里插入图片描述

  13. 网关条件判断条件–通过
    在这里插入图片描述

  14. 当我们画好图后,【*.bpmn20.xml】流程文件也已经创建成功了
    在这里插入图片描述

  15. 可以书写针对流程的逻辑了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/672358.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

这些企业已经有了HCM系统,为什么还要再单独上考勤系统?

最近有几家制造业和零售业的朋友咨询我考勤管理系统选型的问题&#xff0c;都集中在WFM方面的考勤咨询。 奇怪的是这些企业基本上都有一定的HR数字化基础&#xff0c;也上了HR主系统&#xff0c;甚至也实施了考勤系统&#xff0c;那为什么还要再上一个考勤系统呢&#xff1f; …

node cool-admin 后端宝塔面板看代码日志

1.需求 我在处理回调问题的时候 就是找不到问题&#xff0c;因为不像本地的代码 控制台能够直接打印出来问题&#xff0c;你是放在线上了 所以那个日志不好打印 我看网上都说是 直接用一个loger.js 打印 日志 放到代码文件里 这种方法也许有用 但是对我这框架cool来说 试了没有…

LabVIEW高精度主动模拟肺系统的开发与应用

在医疗设备的研发与测试中&#xff0c;高精度主动模拟肺系统扮演了不可或缺的角色。这种系统能够精确模拟人体的呼吸过程&#xff0c;对于呼吸机性能的测试、医疗人员的培训以及临床研究具有极其重要的意义。通过利用先进的硬件控制技术和软件算法&#xff0c;主动模拟肺系统能…

Pandas文本数据处理技术指南—从查找到时间序列分析【第66篇—python:文本数据处理】

文章目录 Pandas文本数据处理技术指南引言 1. 查找文本数据2. 替换文本数据3. 拼接文本数据4. 正则表达式操作5. 虚拟变量6. 处理缺失值7. 分割文本数据8. 字符串处理方法9. 文本数据的合并与连接10. 文本数据的排序11. 文本数据的统计分析12. 文本数据的分组与聚合13. 文本数据…

Java之泛型系列--继承父类与实现多个接口(有示例)

原文网址&#xff1a;Java之泛型系列--继承父类与实现多个接口(有示例)_IT利刃出鞘的博客-CSDN博客 简介 本文介绍java如何用泛型表示继承父类并实现多个接口。 用泛型表示某个类是某个类的子类或者实现了接口的方法为&#xff1a;<T extends A & B & C> 用…

瑞芯微推理RKNN使用

参考资料 toolkit2 官网资料 野火实践指南 Ubuntu22.04实践 安装toolkit2 安装命令pip3 install -r xxx/packages/requirements_cp310-1.6.0.txt pip3 install xxx/packages/rknn_toolkit2-1.6.081f21f4d-cp310-cp310-linux_x86_64.whl注意加上 -i xxx 可能会造成下载tf-es…

react中hook封装一个table组件

目录 react中hook封装一个table组件依赖CommonTable / index.tsx使用组件效果 react中hook封装一个table组件 依赖 cnpm i react-resizable --save cnpm i ahooks cnpm i --save-dev types/react-resizableCommonTable / index.tsx import React, { useEffect, useMemo, use…

4. ⼤模型微调方法

到底有哪些微调⽅法呢&#xff1f; 第⼀类⽅法&#xff1a;借助OpenAI提供的在线微调⼯具进⾏微调&#xff1b;第⼆类⽅法&#xff1a;借助开源微调框架进⾏微调&#xff1b; 1. OpenAI在线微调⼯具 网址&#xff1a;https://platform.openai.com/docs/guides/fine-tuning/c…

跟着GPT学设计模式之原型模式

如果对象的创建成本比较大&#xff0c;而同一个类的不同对象之间差别不大&#xff08;大部分字段都相同&#xff09;&#xff0c;在这种情况下&#xff0c;我们可以利用对已有对象&#xff08;原型&#xff09;进行复制&#xff08;或者叫拷贝&#xff09;的方式来创建新对象&a…

EasyRecovery2024永久免费版电脑数据恢复软件下载

EasyRecovery数据恢复软件是一款非常好用且功能全面的工具&#xff0c;它能帮助用户恢复各种丢失或误删除的数据。以下是关于EasyRecovery的详细功能介绍以及下载步骤&#xff1a; EasyRecovery-mac最新版本下载:https://wm.makeding.com/iclk/?zoneid50201 EasyRecovery-win…

C++中的时间工具

目录 编译期有理数持续时间 duration时钟时间点 本文主要记录C标准中提供的时间处理工具&#xff0c;并提供简单实现的Linux平台的定时器demo C标准库中的chrono库提供了处理时间和日期相关的功能&#xff0c;头文件&#xff1a;#include<chrono>&#xff1b;这个库包含以…

一台Mac同时安装vue2和vue3

背景&#xff1a;电脑需要运行vue2和vue3项目&#xff0c;就得同时有vue2和vue3环境&#xff0c;之前以配置好vue2了&#xff0c;现在增加vue3 1. 新建一个安装vue3的目录 进入vue3文件夹安装vue3 // 注意这里没有参数-g&#xff0c;因为-g全局安装的命令 npm install vue/cli…

Yearning审核平台本地安装配置并结合内网穿透实现远程访问

文章目录 前言1. Linux 部署Yearning2. 本地访问Yearning3. Linux 安装cpolar4. 配置Yearning公网访问地址5. 公网远程访问Yearning管理界面6. 固定Yearning公网地址 前言 Yearning 简单, 高效的MYSQL 审计平台 一款MYSQL SQL语句/查询审计工具&#xff0c;为DBA与开发人员使用…

Linux的Vi编辑器显示行数

前言 要在Vi编辑器中显示行数&#xff0c;您可以使用以下方法&#xff1a; 临时显示 进入Vi编辑器。按下 Esc 键确保你处于普通模式。输入 :set number 并按下 Enter 键。 这样就会在Vi编辑器的左侧显示行号。如果想要关闭行号显示&#xff0c;可以输入 :set nonumber 并…

Rust安装——Win10

安装步骤 1、下载RUSTUP-INIT.EXE&#xff08;64-BIT&#xff09; 2、由于国外源下载依赖太慢&#xff0c;因此建议增加win10环境变量配置国内源&#xff0c;增加RUSTUP_DIST_SERVER、RUSTUP_UPDATE_ROOT环境变量即可 RUSTUP_DIST_SERVER随便选择其中的一个源就行&#xff0c;…

人工智能|深度学习——使用多层级注意力机制和keras实现问题分类

代码下载 使用多层级注意力机制和keras实现问题分类资源-CSDN文库 1 准备工作 1.1 什么是词向量? ”词向量”&#xff08;词嵌入&#xff09;是将一类将词的语义映射到向量空间中去的自然语言处理技术。即将一个词用特定的向量来表示&#xff0c;向量之间的距离&#xff08;例…

学习感觉累 速度慢 反应迟钝 容易忘记 说话累 学习的后勤保障

学习的后勤保障 1、睡眠质量 2、精神勿过度紧张 3、过度用脑 4、适量运动 5、营养充足 6、保持新鲜生活每一天 7、简约生活&#xff0c;适中。 8、保持各方面状态良好 身体比较虚弱&#xff0c;气血不足&#xff0c;说话没几句就很累。 身体虚弱和气血不足的问题需要从多方面…

2.6学习总结10

动态规划 知识点 动态规划是一种解决问题的策略&#xff0c;适用于具有重叠子问题和最优子结构性质的问题。 动态规划的基本思想是将原问题分解为一系列子问题&#xff0c;通过求解子问题的最优解来得到原问题的最优解。在求解子问题时&#xff0c;利用已经求解过的子问题的…

力扣热门100题 - 3.无重复字符的最长子串

力扣热门100题 - 3.无重复字符的最长子串 题目描述&#xff1a;示例&#xff1a;提示&#xff1a;解题思路 &#xff08;滑动窗口 哈希表&#xff09;&#xff1a;代码&#xff1a; 题目链接&#xff1a;3. 无重复字符的最长子串 题目描述&#xff1a; 给定一个字符串 s &…

step导入到solidworks外观处理方法

在导入到solidworks中的kuka机器人会变成灰色。看上去很不好看。如何才能大体恢复一下原外观呢&#xff1f;主要可以使用如下两种方法。 主要是使用了将里面的形状单独变成零件&#xff0c;方便装配&#xff0c;使机器人可以变化姿态。造成外观颜色丢失。 1.外观复制 如下图所…