文章目录
一.activiti
1.什么是activiti7
业务流程管理项目(BPM)
activiti,是一个工作流引擎,可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言BPMN2.0进行定义,业务流程按照预先定义的流程进行执行,实现了系统的流程由activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统健壮性。
2.activiti7所需要的安装环境
(1)所需jar包
1、activiti-engine-7.0.0.beta1.jar
2、activiti 依赖的 jar 包: mybatis、 alf4j、 log4j 等
3、activiti 依赖的 spring 包
4、mysql数据库驱动(数据库驱动可以更具自己所需而变动,详细参照activiti支持的数据库)
5、第三方数据连接池 dbcp
6、单元测试 Junit-4.12.jar(为了测试使用activiti)
(2)pom.xml
<properties>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<activiti.version>7.0.0.Beta1</activiti.version>
</properties>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn 模型处理 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn 转换 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn json数据转换 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn 布局 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- activiti 云支持 -->
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- 链接池 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
(3)在resources文件夹下创建日志配置文件以及activiti所需配置文件activiti.cfg.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--dbcp连接池-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activiti?serverTimezone=GMT&nullCatalogMeansCurrent=true"/>
<property name="username" value="root"/>
<property name="password" value="19980420"/>
<property name="maxActive" value="3"/>
<property name="maxIdle" value="1"/>
</bean>
<!--在默认方式下,bean的id固定为processEngineConfiguration-->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!--配置数据库连接池-->
<property name="dataSource" ref="dataSource"/>
<!-- 配置数据库相关内容-->
<!-- <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti?serverTimezone=GMT&nullCatalogMeansCurrent=true"/>-->
<!-- <property name="jdbcUsername" value="root"/>-->
<!-- <property name="jdbcPassword" value="19980420"/>-->
<!-- activiti在创建数据库时的策略,为true时,若存在相应的表,则使用,若不存在则创建-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</beans>
日志配置文件
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=f:\act\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
3.Activiti数据库表的自动创建
第一次运行这个代码时自动创建
public class TestCreate {
// 使用activiti提供的默认方法来创建数据库
@Test
public void testCreateDbTable(){
//需要使用activiti的工具类ProcessEngines,使用方法getDefaultProcessEngine,
//getDefaultProcessEngine会默认读取从resources下的activiti.cfg.xml文件中
// 在创建processEngine时,就会创建数据库的表
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
System.out.println(engine);
}
@Test
public void test1() {
//使用下面这种方式生成表的条件
//1.activiti配置文件名称必须为activiti.cfg.xml
//2.activiti.cfg.xml中bean的id必须为"processEngineConfiguration"
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
System.out.println(engine );
}
@Test
public void test2() {
//1.创建ProcessEngineConfiguration对象
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
//2.创建ProcessEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
System.out.println(processEngine);
}
4.Activiti各表的意义
表分类 | 表名 | 解释 |
一般数据 | ||
[ACT_GE_BYTEARRAY] | 通用的流程定义和流程资源,例如bpmn对应的xml文件以及png文件 | |
[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] | 运行时变量表 |
5.创建流程引擎
(1)默认方法
//1.activiti配置文件名称必须为activiti.cfg.xml
//2.activiti.cfg.xml中bean的id必须为"processEngineConfiguration"
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
System.out.println(engine );
(2)自定义方法
配置文件名称可以自定义,bean的名称也可以自定义
//1.创建ProcessEngineConfiguration对象
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml",processEngineConfiguration);
//2.创建ProcessEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
System.out.println(processEngine);
6.service服务接口
(1)service创建方式
HistoryService historyService = processEngine.getHistoryService();
ManagementService managementService = processEngine.getManagementService();
RepositoryService repositoryService = processEngine.getRepositoryService();
(2)service总览
service名称 | service作用 |
RepositoryService | activiti资源管理类 |
HistoryService | activiti历史管理类 |
RunTimeService | activiti流程运行管理类 |
TaskService | activiti任务管理类 |
ManageService | activiti引擎管理类 |
7.流程定义
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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/processdef">
<process id="evection_1" name="evection" isExecutable="true">
<startEvent id="_2" name="StartEvent"/>
<userTask activiti:assignee="zhangsan" activiti:exclusive="true" id="_3" name="创建出差申请"/>
<userTask activiti:assignee="jerry" activiti:exclusive="true" id="_4" name="经理审批"/>
<userTask activiti:assignee="jack" activiti:exclusive="true" id="_5" name="总经理审批"/>
<userTask activiti:assignee="rose" activiti:exclusive="true" id="_6" name="财务审批"/>
<endEvent id="_7" name="EndEvent"/>
<sequenceFlow id="_8" sourceRef="_2" targetRef="_3"/>
<sequenceFlow id="_9" sourceRef="_3" targetRef="_4"/>
<sequenceFlow id="_10" sourceRef="_4" targetRef="_5"/>
<sequenceFlow id="_11" sourceRef="_5" targetRef="_6"/>
<sequenceFlow id="_12" sourceRef="_6" targetRef="_7"/>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_evection">
<bpmndi:BPMNPlane bpmnElement="evection_1" id="BPMNPlane_evection">
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
8.流程部署
(1)部署代码
// 1.创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2.获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3.使用service进行流程部署,定义一个流程的名字,把bpmn和png都存储到数据库里
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程")
.addClasspathResource("bpmn/evection.bpmn20.xml")
.addClasspathResource("bpmn/evection.bpmn20.png")
.deploy();
// 4.输出模型信息
System.out.println("流程部署id="+deploy.getId());
System.out.println("流程部署name="+deploy.getName());
(2)部署影响的数据库表
新增:
ACT_RE_DEPLOYMENT
,流程部署表。每部署一次都增加一条记录
ACT_RE_PROCDEF
,流程定义表,生成流程定义信息
ACT_GE_BYTEARRAY
,流程资源表,例如xml和png文件
更新:
ACT_GE_PROPERTY
数据库中deployment和procdef是一对多的关系。
(3)zip方式进行流程部署
@Test
public void testDeploymentByZip(){
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("bpmn/evection.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
Deployment deploy = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.deploy();
}
9.启动流程实例
(1)启动代码
public void testStartProcess(){
//1.创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.根据流程定义的id启动流程
ProcessInstance instance = runtimeService.startProcessInstanceByKey("evection_1");
//4.输出内容
System.out.println("流程定义id="+instance.getProcessDefinitionId());
System.out.println("流程实例id="+instance.getId());
System.out.println("当前活动id="+instance.getActivityId());
}
(2)操作的数据库表
ACT_HI_ACTINST,流程实例执行历史
ACT_HI_IDENTITYLINK,流程的参与用户信息历史
ACT_HI_PROCINST,流程实例历史信息
ACT_HI_TASKINST,流程任务历史信息
ACT_RU_EXECUTION,流程正在执行信息
ACT_RU_IDENTITYLINK,流程的参与用户信息
ACT_RU_TASK,任务信息
10.查询个人待执行的任务
(1)代码
public void testPersonTaskList(){
//1.创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取TaskService
TaskService taskService = processEngine.getTaskService();
//3.根据流程key和任务负责人 查询任务
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("evection_1")
.taskAssignee("zhangsan")
.list();
//4.输出内容
for(Task task : taskList){
System.out.println("流程实例id="+task.getProcessInstanceId());
System.out.println("任务id="+task.getId());
System.out.println("任务负责人="+task.getAssignee());
System.out.println("任务名称="+task.getName());
}
}
}
11.完成个人待办任务
(1)代码
public void completeTask(){
//1.创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取TaskService
TaskService taskService = processEngine.getTaskService();
//3.根据任务id完成任务
//taskService.complete("7505");
//3.查询出任务id完成任务 根据jerry evection_1查询对应的任务
Task task = taskService.createTaskQuery()
.processDefinitionKey("evection_1")
.taskAssignee("jerry")
.singleResult();
System.out.println("流程实例id="+task.getProcessInstanceId());
System.out.println("任务id="+task.getId());
System.out.println("任务负责人="+task.getAssignee());
System.out.println("任务名称="+task.getName());
taskService.complete(task.getId());
}
12.查询流程定义
//查询流程定义
@Test
public void queryProcessDefinition(){
//1.创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取ReposityService
RepositoryService taskService = processEngine.getRepositoryService();
//3.获取processDefinitionQuery对象
ProcessDefinitionQuery processDefinitionQuery = taskService.createProcessDefinitionQuery();
//4.查询当前所有的流程定义,返回流程定义信息的集合
List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey("evection_1")
.orderByProcessDefinitionVersion()
.desc()
.list();
for (ProcessDefinition processDefinition : list) {
System.out.println("流程定义id="+processDefinition.getId());
System.out.println("流程定义名称="+processDefinition.getName());
System.out.println("流程定义key="+processDefinition.getKey());
System.out.println("流程定义version="+processDefinition.getVersion());
}
}
13.删除流程部署
删除流程定义时,不会删除历史信息
//删除流程
@Test
public void deleteProcess(){
//1.创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取ReposityService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.通过流程部署id删除流程
String deploymentId = "1";
repositoryService.deleteDeployment(deploymentId);
//如果当前流程中有未执行完的,想要删除的话需要使用特殊方式,原理就是 级联删除, 为true,则执行级联删除
repositoryService.deleteDeployment(deploymentId,true);
}
14.下载部署文件
public void download() throws IOException {
//1.创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取ReposityService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.获取processDefinitionQuery对象
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
//4.查询流程部署id
ProcessDefinition result = processDefinitionQuery.processDefinitionKey("evection_1")
.singleResult();
String deploymentId = result.getDeploymentId();
//5.通过repositoryService,传递部署id参数,读取资源信息(png,xml)
//5.1获取png的流 我的数据库中没有上传图片
// String diagramResourceName = result.getDiagramResourceName();
// InputStream pngStream = repositoryService.getResourceAsStream(deploymentId, diagramResourceName);
//5.2获取xml的流
String resourceName = result.getResourceName();
InputStream xmlInput = repositoryService.getResourceAsStream(deploymentId, resourceName);
//6.构造outputStream流
File xmlFile = new File("d:/DownApp/Java/evection.xml");
FileOutputStream xmlOutput = new FileOutputStream(xmlFile);
//7.输入流和输出流的转换
IOUtils.copy(xmlInput,xmlOutput);
//8.关闭流
xmlOutput.close();
xmlInput.close();
}
15.查看历史信息
public void queryHistoryInfo(){
//1.创建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取HistoryService
HistoryService historyService = processEngine.getHistoryService();
//3.获取actinst表的查询对象
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
//4.查询actinst表
historicActivityInstanceQuery.processInstanceId("5001");
//4.1增加排序操作
historicActivityInstanceQuery.orderByHistoricActivityInstanceStartTime().asc();
//5.查询所有内容
List<HistoricActivityInstance> list = historicActivityInstanceQuery.list();
//6.输出
for (HistoricActivityInstance historicActivityInstance : list) {
System.out.println("流程定义id="+historicActivityInstance.getProcessDefinitionId());
System.out.println("流程活动id="+historicActivityInstance.getActivityId());
System.out.println("流程名称="+historicActivityInstance.getActivityName());
System.out.println("==========================");
}
}
16.activiti和业务系统整合
(1)添加businesskey到activiti表中
影响ACT_RU_EXECUTION
public void addBusinessKey(){
//1.获得流程引擎
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
//2.获得对应的service
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
//3.启动流程的过程中,添加bussinessKey
//第一个参数:流程定义的key,第二个参数:businessKey,存出差申请单的id
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("evection_1", "1001");
//4.输出
System.out.println(processInstance.getBusinessKey());
}
(2)流程的挂起与激活
一个流程定义下的所有流程实例的激活和挂起
在数据库中,1表示激活状态,2表示挂起状态
public void suspendAllProcess(){
//1.获得流程引擎
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
//2.获得对应的service
RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
//3.根据流程定义的key获取流程定义信息
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()//获取流程定义查询对象
.processDefinitionKey("evection_1")
.singleResult();
// 4.查询当前流程定义的实例是否都处于挂起状态
boolean suspended = processDefinition.isSuspended();
// 5、获取流程定义的id
String definitionId = processDefinition.getId();
// 6.如或是挂起状态,则改为激活
if(suspended){
//参数一:流程定义id,参数二:是否激活,参数三:激活时间
repositoryService.activateProcessDefinitionById(definitionId,true,null);
System.out.println("流程定义id+"+definitionId+"已激活");
}
// 7.若是激活状态,则改为挂起
else{
//参数一:流程定义id,参数二:是否暂停,参数三:暂停时间
repositoryService.suspendProcessDefinitionById(definitionId,true,null);
System.out.println("流程定义id+"+definitionId+"已挂起");
}
}
单个流程实例的挂起和激活
public void suspendSingleProcess() {
//1.获得流程引擎
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
//2.获得对应的service
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
//3.获取流程实例对象
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId("7501")
.singleResult();
// 4.得到当前流程实例的暂停状态
boolean suspended = processInstance.isSuspended();
// 5.获取流程实例id
String processInstanceId = processInstance.getProcessInstanceId();
// 6、如果暂停,则激活
if(suspended){
runtimeService.activateProcessInstanceById(processInstanceId);
System.out.println("流程实例:"+processInstanceId+"已激活");
}else{
runtimeService.suspendProcessInstanceById(processInstanceId);
System.out.println("流程实例:"+processInstanceId+"已挂起");
}
// 7.如果激活,则挂起
}
17.个人任务
(1)分配任务负责人
固定分配
直接指定任务负责人
表达式分配
- UEL-VALUE
${assignee}
- UEL-METHOD
${userbean.getUserId()}
-
UEL-VALUE和UEL-METHODS结合
-
其他
编写代码配置负责人
二.监听器
1.任务监听器
(1)定义
任务监听器用于在特定的任务相关事件发生时,执行自定义的Java逻辑或表达式。任务监听器会经历assignment、create、complete、delete
。当流程引擎触发这四种事件类型时,对应的任务监听器会捕获其事件类型,再按照监听器的处理逻辑进行处理。
(2)xml文件配置
<userTask activiti:exclusive="true" id="_3" name="创建出差申请">
<extensionElements>
<activiti:taskListener event="create" class="com.xu.listener.myTaskListener" />
</extensionElements>
</userTask>
(3)使用监听器指定任务负责人
/**
* 任务监听器用于在特定的任务相关事件发生时,执行自定义的Java逻辑或表达式
*
* 任务监听器支持下列属性:
* event(事件)(必填):任务监听器将被调用的任务事件类型。可用的事件有:
* create(创建):当任务已经创建,并且所有任务参数都已经设置时触发。
* assignment(指派):当任务已经指派给某人时触发。请注意:当流程执行到达用户任务时,create事件触发前,首先触发
* assignment事件。这看起来不是自然顺序,但是有实际原因的:当收到create事件时,我们通常希望查看任务的所有参数,包括
* 办理人。
* complete(完成):当任务已经完成,从运行时数据中删除前触发。
* delete(删除):在任务即将被删除前触发。请注意当任务通过completeTask正常完成时也会触发
*注意:assignment事件比create先执行。
* class:需要调用的代理类。这个类必须实现 org.activiti.engine.delegate.TaskListener 接口
*
*
* expression:(不能与class属性一起使用):指定在事件发生时要执行的表达式。可以为被调用的对象传递 DelegateTask 对象与事件名(使用 task.eventName )作为参数
*
*
*
* delegateExpression:可以指定一个能够解析为 TaskListener 接口实现类对象的表达式。与服务任务类似
*
*
*/
public class myTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
// 测试监听器
System.out.println("============TaskListener start============");
String taskDefinitionKey = delegateTask.getTaskDefinitionKey();
String eventName = delegateTask.getEventName();
System.out.println("事件名称:" + eventName);
System.out.println("taskDefinitionKey:" + taskDefinitionKey);
System.out.println("============TaskListener end============");
//指定负责人
if("创建出差申请".equals(delegateTask.getName()) && "create".equals(delegateTask.getEventName()) ){
delegateTask.setAssignee("zhangsan");
}
}
}
2.执行监听器
(1)定义
执行监听器则监听流程的所有节点和连线。主要有start、end、take事件。其中节点有start、end两种事件,而连线则有take事件。下图是执行监听器的生命周期:
三.流程变量
1.定义
流程变量(key —value)在整个工作流中扮演很重要的作用。例如:请假流程中有请假天数、请假原因等一些参数都为流程变量的范围。流程变量的作用域范围是只对应一个流程实例。也就是说各个流程实例的流程变量是不相互影响的。流程实例结束完成以后流程变量还保存在数据库中(存放到流程变量的历史表中)。
注意:虽然流程变量中可以存储业务数据可以通过activiti的api查询流程变量从而实现 查询业务数据,但是不建议这样使用,因为业务数据查询由业务系统负责,activiti设置流程变量是为了流程执行需要而创建。
2.流程变量支持的类型
如果将 pojo 存储到流程变量中,必须实现序列化接口 serializable,为了防止由于新增字段无法反序列化,需要生成 serialVersionUID。
3.流程变量作用域
流程变量的作用域可以是一个流程实例(processInstance),或一个任务(task),或一个执行实例(execution)
(1)globa变量
流程变量的默认作用域是流程实例。当一个流程变量的作用域为流程实例时,可以称为 global 变量
注意:
如: Global变量:userId(变量名)、zhangsan(变量值)
global 变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。
(2)local变量
任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。
Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名也可以和 global 变量名相同,没有影响。
4.流程变量的使用方法
(1)在属性上使用UEL表达式
可以在 assignee 处设置 UEL 表达式,表达式的值为任务的负责人,比如: ${assignee}, assignee 就是一个流程变量名称。
Activiti获取UEL表达式的值,即流程变量assignee的值 ,将assignee的值作为任务的负责人进行任务分配
(2)在连线上使用UEL表达式
可以在连线上设置UEL表达式,决定流程走向。
比如:${price<10000} 。price就是一个流程变量名称,uel表达式结果类型为布尔类型。
如果UEL表达式是true,要决定 流程执行走向。
5.测试全局流程变量
如果在连线上没有设置全局变量,那么两个分支都执行
在部门经理审核前设置流程变量,变量值为出差单信息(包括出差天数),部门经理审核后可以根据流程变量的值决定流程走向。
在设置流程变量时,可以在启动流程时设置,也可以在任务办理时设置
(1)启动流程时设置变量
创建出差申请pojo对象
package com.xu.pojo;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
//出差流程中的流程变量
public class Evection implements Serializable {
// 主键id
private Long id;
// 出差单的名字
private String evectionName;
// 出差天数
private Double days;
// 出差开始时间
private Date beginTime;
private Date endTime;
// 目的地
private String destination;
// 出差原因
private String reason;
}
启动流程并设置变量
在启动流程时设置流程变量,变量的作用域是整个流程实例。
通过Map<key,value>设置流程变量,map中可以设置多个变量,这个key就是流程变量的名字。
//开始流程
@Test
public void startProcess(){
// 1、获取流程引擎
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取runtimeservice
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
// 流程变量的map
Map<String, Object> map = new HashMap<>();
// 3、设置流程变量
Evection evection = new Evection();
evection.setDays(2d);
// 把流程变量的pojo放入map,key对应的是流程图中设置的condition evection.days<3
map.put("evection",evection);
// 4、设置任务的负责人
map.put("assignee0","zhangdan");
map.put("assignee1","经理");
map.put("assignee2","总经理");
map.put("assignee3","人力");
// 5、启动流程
runtimeService.startProcessInstanceByKey("evection-global",map);
}
完成任务,根据流程定义的key和此时的任务负责人
// 执行流程任务
@Test
public void completeTask(){
// 1、获取流程引擎
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取taskservice
TaskService taskService = defaultProcessEngine.getTaskService();
//3、根据流程定义的key和执行任务的负责人查询流程定义
Task task = taskService.createTaskQuery()
.processDefinitionKey("evection-global")
.taskAssignee("经理")
.singleResult();
//4、如果该负责人下并没有关于这个流程的任务,即为空,不执行
System.out.println(task.getId());
if(task != null)
taskService.complete(task.getId());
}
(2)任务办理时设置变量
在完成任务时设置流程变量,该流程变量只有在该任务完成后其它结点才可使用该变量,它的作用域是整个流程实例,如果设置的流程变量的key在流程实例中已存在相同的名字则后设置的变量替换前边设置的变量。
public void completeFenzhiTask(){
// 1、获取流程引擎
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取taskservice
TaskService taskService = defaultProcessEngine.getTaskService();
// 3.设置流程变量,<3 >=3
Map<String, Object> map = new HashMap<>();
Evection evection = new Evection();
evection.setDays(2d);
// 把流程变量的pojo放入map,key对应的是流程图中设置的condition evection.days<3
map.put("evection",evection);
//4、根据流程定义的key和执行任务的负责人查询流程定义
Task task = taskService.createTaskQuery()
.processDefinitionKey("evection-global")
.taskAssignee("经理1")
.singleResult();
//5、如果该负责人下并没有关于这个流程的任务,即为空,不执行
System.out.println(task.getId());
if(task != null)
taskService.complete(task.getId(),map);
}
(3)通过当前流程实例设置变量
通过流程实例id设置全局变量,该流程实例必须未执行完成。
runtimeService.setVariable(executionId,)
(4)通过当前任务设置
taskService.setVariable(executionId,)
6.测试local局部变量
(1)任务办理时设置
任务办理时设置local流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无法在当前流程实例使用,可以通过查询历史任务查询
/*
*处理任务时设置local流程变量
*/
@Test
public void completTask() {
//任务id
String taskId = "1404";
// 获取processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
// 定义流程变量
Map<String, Object> variables = new HashMap<String, Object>();
Evection evection = new Evection ();
evection.setNum(3d);
// 定义流程变量
Map<String, Object> variables = new HashMap<String, Object>();
// 变量名是holiday,变量值是holiday对象
variables.put("evection", evection);
// 设置local变量,作用域为该任务
taskService.setVariablesLocal(taskId, variables);
// 完成任务
taskService.complete(taskId);
}
(2)通过当前任务设置
@Test
public void setLocalVariableByTaskId(){
// 当前待办任务id
String taskId="1404";
// 获取processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Evection evection = new Evection ();
evection.setNum(3d);
// 通过任务设置流程变量
taskService.setVariableLocal(taskId, "evection", evection);
// 一次设置多个值
//taskService.setVariablesLocal(taskId, variables)
}
四.组任务
1.需求
在流程定义中在任务结点的 assignee 固定设置任务负责人,在流程定义时将参与者固定设置在.bpmn20.xml 文件中,如果临时任务负责人变更则需要修改流程定义,系统可扩展性差。
2.xml文件
<userTask activiti:candidateUsers="zhangsan,lisi,wangwu" activiti:exclusive="true" id="_3" name="创建出差申请"/>
3.组任务办理流程
(1)查询组任务
指定候选人,查询该候选人当前的待办任务。
候选人不能立即办理任务。
//查询组任务
@Test
public void findGroupTaskList(){
String candidateUser = "lisi";
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
List<Task> taskLists = taskService.createTaskQuery()
.processDefinitionKey("evection_candidate")
.taskCandidateUser(candidateUser)
.list();
for (Task taskList : taskLists) {
System.out.println("流程实例id="+taskList.getProcessInstanceId());
System.out.println("任务id="+taskList.getId());
System.out.println("任务负责人="+taskList.getAssignee());
}
}
数据库查询语句
select distinct RES.* from ACT_RU_TASK RES inner join ACT_RU_IDENTITYLINK I on I.TASK_ID_ = RES.ID_ inner join ACT_RE_PROCDEF D on RES.PROC_DEF_ID_ = D.ID_ WHERE D.KEY_ = ? and RES.ASSIGNEE_ is null and I.TYPE_ = 'candidate' and ( I.USER_ID_ = ? ) order by RES.ID_ asc LIMIT ? OFFSET ?
(2)拾取(claim)任务
该组任务的所有候选人都能拾取。
将候选人的组任务,变成个人任务。原来候选人就变成了该任务的负责人。
如果拾取后不想办理该任务?
需要将已经拾取的个人任务归还到组里边,将个人任务变成了组任务。
//候选人拾取任务
@Test
public void claimTask(){
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
//当前任务的id
String taskId = "52502";
//任务候选人
String candidateUser = "lisi";
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskCandidateUser(candidateUser)
.singleResult();
if(task != null){
//拾取
taskService.claim(taskId,candidateUser);
System.out.println("任务拾取完成"+taskId+"用户"+candidateUser);
}
}
(3)查询个人任务
查询方式同个人任务部分,根据assignee查询用户负责的个人任务。
(4)办理个人任务
(5)归还任务到组任务
//任务的归还
@Test
public void backTask(){
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
//当前任务的id
String taskId = "52502";
//任务候选人
String assignee = "lisi";
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(assignee)
.singleResult();
if(task != null){
//归还任务,就是把负责人那列设置为空
taskService.setAssignee(taskId,null);
System.out.println("任务归还完成"+taskId);
}
}
(6)任务交接
@Test
public void changeCandidate(){
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = defaultProcessEngine.getTaskService();
//当前任务的id
String taskId = "52502";
//任务候选人
String assignee = "lisi";
String candidateUser = "wangwu";
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(assignee)
.singleResult();
if(task != null){
taskService.setAssignee(taskId,candidateUser);
System.out.println("任务交接完成"+taskId);
}
}
五.网关
1、排他网关ExclusiveGateway
用来对流程中的决定进行建模,流程执行到该网关时,按照输出流的顺序逐个计算,当条件为true时,继续执行当前网关的输出流。
如果多个线路的计算结果都为true,那么只会执行第一个值为true(id较小)的网关,忽略其他表达式的值为true的网关。如果多个网关计算结果没有为true的值,则引擎会抛出异常。
2、并行网关parallelGateway
并行网关不会解析条件,即使在并行网关的顺序流中定义了条件,也会被忽略
并行网关用来对并发的任务进行流程建模,它能把单条线路任务拆分(fork)成多个路径并行执行或将多条线路合并(join).
并行网关的功能取决于输入、输出顺序流:
拆分:并行执行所有的输出顺序流,并且为每一条顺序流创建一个并行执行路线;
合并:所有从并行网关拆分并执行完成的线路均再次等候,知道所有的线路都执行完成才继续向下执行。
并行网关还允许在线路上嵌套并行网关,也就是在fork拆分的线路上再添加n个fork线路,只要保证最后又一个join点合并拆分的线路即可。
3.包含网关inclusiveGateway
包容网关融合了排他网关和并行网关的特性,排他网关允许在每条线路上设置条件,并行网关可以同时执行多条线路,包容网关即可以同时执行多条线路,又允许再网关上设置条件。
例如,在一个网关中,大于3天给经理审批,小于三天给副总经理审批,而所有的申请都要人事审批
拆分:计算每条线路上的表达式,当表达式计算结果为true时,创建一个并线线路并继续执行;
合并:所有从并行网关拆分并执行完成的线路均再次等候,直到所有的线路都执行了才继续向下执行。
4.事件网关
事件网关是专门为中间捕获事件设置的,它允许设置多个输出流指向多个不同的中间捕获事件(最少2个)。在流程执行到事件网关后,流程处于“等待”状态,因为中间捕获事件需要依赖中间抛出事件触发才能更改“等待”状态为“活动”状态,定时器捕获事件除外(它由时间驱动)。
关于事件网关需要注意几点:
1、事件网关的输出流数量必须大于2个;
2、事件网关的输出流类型只能是中间捕获事件,activiti不支持接受任务后面的事件网关;
3、中间捕获事件的输出流只能有一个。
六.activiti和第三方整合
1.和spring整合
(1)pom.xml引入
<properties>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>alfresco</id>
<name>Activiti Releases</name>
<url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
(2)创建activiti和spring整合的配置文件activiti-spring.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activit7?useUnicode=true&characterEncoding=UTF-8&nullCatalogMeansCurrent=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="maxActive" value="3" />
<property name="maxIdle" value="1" />
</bean>
<!-- 工作流引擎配置bean -->
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 使用spring事务管理器 -->
<property name="transactionManager" ref="transactionManager"/>
<!--flase: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。(生产
环境常用)
true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。(开发时常用)
create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。(单元测试常用)
drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)。-->
<!-- 数据库策略 -->
<!-- <property name="databaseSchemaUpdate" value="drop-create"/>-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
<!-- 流程引擎 -->
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration"/>
</bean>
<!-- 资源服务service -->
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
<!-- 流程运行service -->
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
<!-- 任务管理service -->
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
<!-- 历史管理service -->
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 切面,根据具体项目修改切点配置
<aop:config proxy-target-class="true">
<aop:advisor advice-ref="txAdvice"
pointcut="execution(*com.itheima.service.impl..(..))"/>
</aop:config>-->
</beans>
2.和springboot整合
(1)pom.xml引入
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xu</groupId>
<artifactId>activiti_springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>activiti_springboot</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(2)配置文件application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/activiti?characterEncoding=UTF-8&serverTimeZone=GMT&useUnicode=true
username: root
password: 19980420
activiti:
# flase: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。(生产
# 环境常用)
# true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。(开发时常用)
# create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。(单元测试常用)
# drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
database-schema-update: true
#activiti默认不生成历史信息表,开启历史表
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: true
(3)添加springsecurity安全框架整合配置
添加securityUtil类
因为Activiti7与SpringBoot整合后,默认情况下,集成了SpringSecurity安全框架,这样我们就要去准备SpringSecurity整合进来的相关用户权限配置信息。
SpringBoot的依赖包已经将SpringSecurity的依赖包也添加进项目中。
(4)添加DemoApplicationConfig类
在Activiti7官方下载的Example中找到DemoApplicationConfig类,它的作用是为了实现SpringSecurity框架的用户权限的配置,这样我们就可以在系统中使用用户权限信息。
本次项目中基本是在文件中定义出来的用户信息,当然也可以是数据库中查询的用户权限信息。
后面处理流程时用到的任务负责人,需要添加在这里
/**
* 设置用户和角色
*/
@Configuration
public class DemoApplicationConfiguration {
private Logger logger = LoggerFactory.getLogger(DemoApplicationConfiguration.class);
/**
* 添加Security的用户
* @return
*/
@Bean
public UserDetailsService myUserDetailsService() {
//把用户存储在内存中
InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
//这里添加用户,后面处理流程时用到的任务负责人,需要添加在这里
//构建用户信息
String[][] usersGroupsAndRoles = {
{"jack", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"rose", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"tom", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
{"system", "password", "ROLE_ACTIVITI_USER"},
{"admin", "password", "ROLE_ACTIVITI_ADMIN"},
};
for (String[] user : usersGroupsAndRoles) {
//用户的角色和组
List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
}
return inMemoryUserDetailsManager;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}