概念入门

首先来个定义,什么是工作流?

工作流(Workflow),指“业务过程的部分或整体在计算机应用环境下的自动化”。是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。在计算机中,工作流属于计算机支持的协同工作(CSCW)的一部分。后者是普遍地研究一个群体如何在计算机的帮助下实现协同工作的。

工作流主要解决的主要问题是:为了实现某个业务目标,利用计算机在多个参与者之间按某种预定规则自动传递文档、信息或者任务。

看不懂?没关系,先来张图:

qingjia.png

假设这是一张请假流程图,请假申请需要先提交给部门经理,部门经理同意后再转到总经理审核,部门经理没同意之前总经理是看不到这个请假申请的。

如果你是一个程序开发人员,想一想你会怎么开发这个系统?

通常情况下我们用许多的状态量来标识申请流程走到哪一步了。比如:

状态值描述
0请假申请已提交
1部门经理拒绝
2部门经理同意,到总经理
3总经理拒绝
4总经理同意,下一步
。。。。。。

很繁琐对吧?如果有多种流程,现有流程修改,任务量更会艰巨,所以,需要有一个工作流系统来帮助简化工作。

Activiti7就是这么一个工作流系统

可以这么理解:

Activiti对于工作流 相当于 Mysql对于关系型数据,前者的存在是为了更好的管理和使用后者。

当然,这是概念上的一些描述,事实上,Activiti就是一些jar包,它是使用Java语言开发的,用于简化,管理工作流开发的工作流引擎。

那Activity为什么能简化工作流开发呢?

在介绍Activiti之前,先来了解一下BPMN(Business Process Model and Notation),它是一种用来描述业务流程图的符号语言,类似于UML。

PS:BPMN相关的专业概念先不去看了,就像每个程序猿都会写SQL,但是四大范式,内模式,外模式那些专业概念不去看一时半会也说不上来,所以会用就行啦。

BPMN 是目前被各 BPM 厂商广泛接受的 BPM 标准。Activiti 就是使用 BPMN 2.0 进行流程建模、流程执行管理,它包括很多的建模符号,比如:

Event

用一个圆圈表示,它是流程中运行过程中发生的事情。

clipimage0021573894954565.jpg

活动用圆角矩形表示,一个流程由一个活动或多个活动组成

clipimage0021573894978125.jpg

Bpmn图形其实是通过xml表示业务流程,上边的.bpmn文件使用文本编辑器打开:

  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:activiti="http://activiti.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.activiti.org/test">
   <process id="myProcess" name="My process" isExecutable="true">
     <startEvent id="startevent1" name="Start">startEvent>
     <userTask id="usertask1" name="创建请假单">userTask>
     <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1">sequenceFlow>
     <userTask id="usertask2" name="部门经理审核">userTask>
     <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2">sequenceFlow>
     <userTask id="usertask3" name="人事复核">userTask>
     <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3">sequenceFlow>
     <endEvent id="endevent1" name="End">endEvent>
     <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1">sequenceFlow>
   process>
   <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
     <bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
       <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
         <omgdc:Bounds height="35.0" width="35.0" x="130.0" y="160.0">omgdc:Bounds>
       bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
         <omgdc:Bounds height="55.0" width="105.0" x="210.0" y="150.0">omgdc:Bounds>
       bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
         <omgdc:Bounds height="55.0" width="105.0" x="360.0" y="150.0">omgdc:Bounds>
       bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
         <omgdc:Bounds height="55.0" width="105.0" x="510.0" y="150.0">omgdc:Bounds>
       bpmndi:BPMNShape>
       <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
         <omgdc:Bounds height="35.0" width="35.0" x="660.0" y="160.0">omgdc:Bounds>
       bpmndi:BPMNShape>
       <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
         <omgdi:waypoint x="165.0" y="177.0">omgdi:waypoint>
         <omgdi:waypoint x="210.0" y="177.0">omgdi:waypoint>
       bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
         <omgdi:waypoint x="315.0" y="177.0">omgdi:waypoint>
         <omgdi:waypoint x="360.0" y="177.0">omgdi:waypoint>
       bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
         <omgdi:waypoint x="465.0" y="177.0">omgdi:waypoint>
         <omgdi:waypoint x="510.0" y="177.0">omgdi:waypoint>
       bpmndi:BPMNEdge>
       <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
         <omgdi:waypoint x="615.0" y="177.0">omgdi:waypoint>
         <omgdi:waypoint x="660.0" y="177.0">omgdi:waypoint>
       bpmndi:BPMNEdge>
     bpmndi:BPMNPlane>
   bpmndi:BPMNDiagram>
 definitions>
 

Activiti部署业务流程定义(.bpmn文件)。使用Activiti提供的api把流程定义内容存进数据库,在Activiti执行过程中可以查询定义的内容。

读者不要被这些符号,代码吓着了,接下来直接上手从代码层面感受一下Activiti的操作与便捷。

环境搭建

目前(2021年3月)Activiti最新版本是Activiti7

官网:https://www.activiti.org/

image20210310215155443.png

读者如果上网搜相关的学习教程,有些是基于Activiti 7.0.0.Beta1版本的,官方直接整合了Spring Boot,我们

直接按照官方教程来学习。

注意:Activiti 7 与Spring Security强耦合,无法排除,所以需要读者有Spring Security的知识

官方提供了很多入门示例https://github.com/Activiti/activiti-examples

一、导入依赖

 <dependencyManagement>
     <dependencies>
         <dependency>
             <groupId>org.activiti.dependenciesgroupId>
             <artifactId>activiti-dependenciesartifactId>
             <version>7.1.0.M5version>
             <scope>importscope>
             <type>pomtype>
         dependency>
     dependencies>
 dependencyManagement>
 <dependency>
     <groupId>org.activitigroupId>
     <artifactId>activiti-spring-boot-starterartifactId>
 dependency>
 <dependency>
     <groupId>mysqlgroupId>
     <artifactId>mysql-connector-javaartifactId>
 dependency>

Activiti的工作管理是通过25张表来实现的,所以这里需要引入数据库驱动

二、配置

添加数据库配置

 spring:
  activiti:
     #1.flase:activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
     #2.true: 默认值。activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建
     #3.create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
     #4.drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
    database-schema-update: true
     #检测历史表是否存在
    db-history-used: true
     #记录历史等级 可配置的历史级别有none, activity, audit, full
    history-level: full
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/activiti7?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8
    username: root
    password: 123456
 

三、编写测试代码

Activiti将之前的底层API抽象成了TaskRuntime和ProcessRuntime,简化了操作。但是,之前说过Activiti与Spring Security强耦合,在使用这两个API之前,要求具有ACTIVITI_USER角色的用户必须已经登录。

image20210310222416938.png

image20210310222325123.png

在官方示例中给出了两个工具类:

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/SecurityUtil.java

https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplicationConfiguration.java

引入这两个工具类

四、编写测试类

 @SpringBootTest
 public class Test {
 
     @Autowired
     private SecurityUtil securityUtil;
 
     @Autowired
     private TaskRuntime taskRuntime;
 
     @Test
     public void test14() {
         // 什么都不用做,只要登录就好了
         securityUtil.logInAs("salaboy");
    }
 }

目录结构这个样子:

image20210311090030601.png

注意注意注意,运行测试后,应该可能一定会出现这个问题:

 ### Error updating database.  Cause: java.sql.SQLSyntaxErrorException: Unknown column 'VERSION_' in 'field list'
 ### The error may exist in org/activiti/db/mapping/entity/Deployment.xml
 ### The error may involve org.activiti.engine.impl.persistence.entity.DeploymentEntityImpl.insertDeployment-Inline
 ### The error occurred while setting parameters
 ### SQL: insert into ACT_RE_DEPLOYMENT(ID_, NAME_, CATEGORY_, KEY_, TENANT_ID_, DEPLOY_TIME_, ENGINE_VERSION_, VERSION_, PROJECT_RELEASE_VERSION_)     values(?, ?, ?, ?, ?, ?, ?, ?, ?)
 ### Cause: java.sql.SQLSyntaxErrorException: Unknown column 'VERSION_' in 'field list'

简直神坑,目前还没有好的办法,只能手动修改ACT_RE_DEPLOYMENT表,添加VERSION,PROJECT_RELEASE_VERSION这两个字段**。

总共会生成25张表

表分类表名解释
一般数据
[ACT_GE_BYTEARRAY]通用的流程定义和流程资源
[ACT_GE_PROPERTY]系统相关属性
流程历史记录
[ACT_HI_ACTINST]历史的流程实例
[ACT_HI_ATTACHMENT]历史的流程附件
[ACT_HI_COMMENT]历史的说明性信息
[ACT_HI_DETAIL]历史的流程运行中的细节信息
[ACT_HI_IDENTITYLINK]历史的流程运行过程中用户关系
[ACT_HI_PROCINST]历史的流程实例
[ACT_HI_TASKINST]历史的任务实例
[ACT_HI_VARINST]历史的流程运行中的变量信息
流程定义表
[ACT_RE_DEPLOYMENT]部署单元信息
[ACT_RE_MODEL]模型信息
[ACT_RE_PROCDEF]已部署的流程定义
运行实例表
[ACT_RU_EVENT_SUBSCR]运行时事件
[ACT_RU_EXECUTION]运行时流程执行实例
[ACT_RU_IDENTITYLINK]运行时用户关系信息,存储任务节点与参与者的相关信息
[ACT_RU_JOB]运行时作业
[ACT_RU_TASK]运行时任务
[ACT_RU_VARIABLE]运行时变量表

现在环境已经搭建好了,先写到这,相关API的操作下次再介绍。