企业中请假一般会和个人假期、工资等挂钩,因此需要对请假过程进行”留痕“处理,具体做法是:员工需要填写一个请假条,写明请假的请假人、时间、缘由等,甚至需要附加证明材料,然后找各级领导进行审批,他的直接领导、领导的领导在上边签字同意,证明不是旷工。
如下图是一个企业中的请假流程:
如果公司规模比较小,可以使用口头请假、纸质请假单,但是当公司达到一定规模时,为了考勤统计、绩效考核、请假证明等原因,需要一个软件系统,用来记录所有员工的请假,员工在使用这个系统时,大致是这样的过程或步骤:
这个过程叫做工作流,工作流简单的讲就是工作的流动,是多个人协作完成一项工作。需要注意的是,在工作流中会涉及到多个角色,每个角色完成不同的任务。
工作流的场景非常多,几乎可以说无处不在,常见工作流场景:
工作流的场景虽然非常多,但是开发的过程确是大同小异。我们来看一个工作流系统的整体结构:
从上图我们可以看到,一个工作流大致包含三部分:
今天要学习的流程审批中心,就是以请假流程的开发为例,系统讲解如何开发一个工作流审批系统,只要掌握了这个系统的开发,以后开发其他业务的审批系统都是相同的过程。
一个工作流系统大致包含以下模块,重点和点是审批模块的开发。幸运的是,工作流引擎正是为了解决这部分难点的。
如果要学习一门技术,首先要掌握这门技术相关的一些概念。
下图以生活中的请假为例,对比了工作流和生活中请假过程的一些概念。
Activiti作为一个框架,提供了一些API,以便于我们开发使用。
Service是Activiti引擎提供用于进行工作流部署、执行、管理的服务接口,我们使用这些接口可以就是操作服务对应的数据表。
请假的业务,是现实生活中非常常见的一个业务,主要包括当事人提交请假,他的直属领导,或更高层的领导来逐个进行审批,最后完成一个请假的过程。每个公司的请假流程细节上可能存在差异,但总体流程都差不多。下面我们一起来看一个简版的请假流程,如下:
create database itcast_workflow default charset utf8mb4;
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.5.0</version>
</parent>
<groupId>com.itheima</groupId>
<artifactId>itcast-workflow</artifactId>
<version>0.0.1</version>
<name>${project.artifactId}</name>
<description>itcast-workflow</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.application.yml
server:
port: 8090
spring:
datasource:
url: jdbc:mysql://localhost:3306/itcast_workflow?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username : root
password : root
driver-class-name: com.mysql.jdbc.Driver
activiti:
#1.flase:默认值。activiti在启动时,对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
#2.true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建
#3.create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
#4.drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
database-schema-update: true
#检测历史表是否存在 activiti7默认没有开启数据库历史记录 启动数据库历史记录
db-history-used: true
#记录历史等级 可配置的历史级别有none, activity, audit, full
#none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
#activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
#audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
#full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等。
history-level: full
#校验流程文件,默认校验resources下的processes文件夹里的流程文件
check-process-definitions: false
#默认采用UUID作为主键, 设置为false, 将采用整型主键
use-strong-uuids: false
#关闭springAutoDeployment自动部署流程定义
deployment-mode: never-fail
logging:
level:
org.activiti.engine.impl.persistence.entity: debug
注意事项:
Mysql 设置区分大小写:
- 修改配置文件my.ini(linux是my.cnf文件),在[mysqld] 后面添加:lower_case_table_names=2
- 注意:
- 5.6: 1---表示不区分大小写 2---表示区分大小写
- 5.7: 1---表示不区分大小写 0---表示区分大小写
4.启动类
package com.itheima.activiti;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Activiti默认集成SpringSecurity安全框架,需要创建UserDetailsService的一个实现类
package com.itheima.activiti.auth;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
return null;
}
}
环境准备好了之后,就可以直接运行启动类,下图中的表会自动被创建(注意:连接的数据库需要自己创建,数据库不会自动创建),Activiti7中自带的数据库表共25张。
数据库表
看到程序运行之后自动创建的表,我们发现Activiti 的表都以 ACT_ 开头。
第二部分是表示表的用途的两个字母标识。 用途也和服务的 API 对应。
表结构说明:
6.测试类
package com.itheima.activiti.test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class ActivitiTest {
}
在测试类中开发案例代码。
使用activiti工作流比较重要的一步就是绘制流程图。最方便的方法就是使用Idea中的插件(actiBPM)进行绘制,叫做离线流程设计器。
安装方式如下:
1). 在线安装
Settings ------> Plugins -----> Marketable ---------> 搜索 actiBPM
安装完成之后,重新启动IDEA 。
**注意: IDEA 2019.1.4之后的版本,无法在线安装此插件 **
2). 离线安装
部分版本的IDEA在Martketplace中搜索不到 actiBPM , 这个时候就选择离线安装 ;
2. 设计请假流程
鼠标右键,选择 “BpmnFile”,创建一个流程图,然后就可以开启绘制。
打开流程设计器,拖动BPMN中的组件,开始绘制。
/**
* 1、保存模型
* 2、保存流程图
* 3、部署模型
* 4、查询流程定义
* 5、启动流程
* 6、执行任务
* 7、查询历史
*/
Activit的模型包含两部分,Model和流程图(文件),本案例保存模型
@Autowired
RepositoryService repositoryService;
/**
* 保存模型对象
*/
@Test
public void saveModel(){
//创建activiti模型对象
Model model = repositoryService.newModel();
model.setKey("myKey");
model.setName("测试保存模型");
//保存流程模型
repositoryService.saveModel(model);
}
流程模型保存在ACT_RE_MODEL表中。
Activit的模型包含两部分,Model和流程图(文件),本案例保存流程图
/**
* 保存流程图
*/
@Test
public void testSaveBpmn() throws IOException {
File file = new File("src/main/resources/holiday.bpmn");
byte[] bytes = FileUtils.readFileToByteArray(file);
repositoryService.addModelEditorSource("15001", bytes);
}
流程图保存在ACT_GE_BYTEARRAY表中:
通常情况下,一些流程是提前规定好的(比如我们的请假流程),此时我们可以提前在我们的流程设计器中将流程先设计出来,再将已设计好的流程定义文件部署到 activti流程引擎中。
/**
* 部署流程
*/
@Test
public void testDeployment(){
repositoryService.createDeployment()
.key("mykey")
.name("简易请假流程")
.addClasspathResource("holiday.bpmn")
.deploy();
}
查询流程部署数据:
1). ACT_RE_PROCDEF:已部署的流程定义
3). ACT_GE_BYTEARRAY:通用的流程定义和流程资源
对于一个流程图,只要key相同,每部署一次将会生成一个流程定义。即一个流程可以有多个流程定义。
/**
* 查询流程定义
*/
@Test
public void testProcessDef(){
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_1")
.list();
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getId());
}
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_1")
.latestVersion().singleResult();
System.out.println(processDefinition.getId());
}
一个流程部署后,生成流程定义,我们可以根据流程定义,发起流程。
/**
* 启动实例
*/
@Autowired
private RuntimeService runtimeService;
@Test
public void testStart(){
runtimeService.startProcessInstanceByKey("myProcess_1");
}
1)ACT_RU_EXECUTION:运行时流程执行实例
2)ACT_RU_TASK:运行时任务
3)ACT_HI_PROCINST: 历史的流程实例
4)ACT_HI_ACTINST:历史的活动实例
5)ACT_HI_TASKINST:历史的任务实例
同样完成任务我们首先就要得到我们用来完成任务的服务类,我们是根据运行时任务表当中的id来完成的。
1). 完成第一步任务
当我们完成当前任务(请假申请),流程就会进入到领导审批。
具体代码如下, task id是ACT_RU_TASK的主键:
/**
* 执行任务
*/
@Autowired
private TaskService taskService;
@Test
public void testComplete(){
taskService.complete("7505");
}
执行完成后:
同样完成领导审批任务(ACT_RU_TASK):
2). 完成第二步任务
当完成当前任务(领导审批)之后,该流程就结束了,流程结束,数据库表 ACT_RU_TASK 中的数据就会被删除。
@Test
public void testComplete(){
taskService.complete("10002");
}
我们可以通过API, 查询当前指定用户, 待处理的任务 ;
/**
* 查询流程历史
*
*/
@Autowired
HistoryService historyService;
@Test
public void testHistory(){
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myProcess_1")
.latestVersion()
.singleResult();
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
.processDefinitionId(processDefinition.getId()).list();
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getActivityName());
}
}
Activiti历史信息很丰富,经常用的是以下几个:
4个核心API,25张表
搭建项目:
maven工程、pom文件、yml文件、创建数据库、Springboot启动类
开发过程:
设计流程、保存模型和流程图、部署流程、启动实例、执行任务、查看历史
点开后的文件添加以下内容:-Dfile.encoding=UTF-8
File -> settings -> Editor -> Enconding
能看见如下图显示就说明成功了