内容来自:

Activiti7工作流引擎视频教程

Activiti的基本用法

pom文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<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>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>

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

配置activiti.cfg.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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: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">

<!--配置数据源dbcp-->
<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/activiti"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>

<!--让activiti单独运行的ProcessEngine的配置,使用单独启动方式,目前没有和Spring整合-->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="dataSource" ref="dataSource"/>
<property name="databaseSchemaUpdate" value="true"/>
</bean>


</beans>

测试代码

1
2
3
4
5
6
7
8
9
/*
//创建一个processEngineConfiguration
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
//创建processEngine对象
ProcessEngine processEngine = configuration.buildProcessEngine();
*/

// 必须满足activiti.cfg.xml和processEngineConfiguration这bean id不变
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();

表的命名规则

Activiti的表都是ACT_开头

  • ACT_RE_*:RE->repository,这个前缀的表包含了流程定义和静态资源
  • ACT_RU_*:RU->runtime,包含流程实例,任务,变量,异步任务,等运行中的数据。只在运行过程中保存,结束就会删除。
  • ACT_HI_*:HI->history,包含历史数据
  • ACT_GE_*:GE->general,包含通用数据
简单的流程定义部署
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//将建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();

//进行部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("diagram/holiday.bpmn")
.name("请假流程")
.deploy();

//输出部署信息
System.out.println(deployment.getName());
System.out.println(deployment.getId());

对应activiti的表:

  •  act_re_deployment:部署信息
    
  •  act_re_procdef:流程定义的一些信息
    
  •  act_ge_bytearray:流程定义的bpmn和png文件
    
简单的启动流程实例
1
2
3
4
5
6
7
8
9
10
11
12
13
//得到ProcessEngin对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//得到RunService对象
RuntimeService runtimeService = processEngine.getRuntimeService();

//创建流程实例 流程定义的key需要知道
ProcessInstance instance = runtimeService.startProcessInstanceByKey("holiday");

//输出实例相关信息
System.out.println("流程定义id" + instance.getProcessDefinitionId());
System.out.println("流程实例id" + instance.getId());
System.out.println("活动id" + instance.getActivityId());

对应activiti的表

  • act_hi_actinst: 已完成的活动

  •  act_hi_identitylink: 参与者信息
    
  •  act_hi_procinst:    流程实例
    
  •  act_hi_taskinst:    任务实例
    
  •  act_ru_execution:   执行表
    
  •  act_ru_identitylink  参与者信息
    
  •  act_ru_task: 任务
    
查询当前用户任务列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//得到TaskService对象
TaskService taskService = processEngine.getTaskService();

//根据流程定义的key,负责人assignee来实现当前用户任务列表查询
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("holiday")
.taskAssignee("zhangsan")
.list();

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());
}
用户处理任务
1
2
3
4
5
6
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

TaskService taskService = processEngine.getTaskService();

//处理,结合当前用户任务列表查询出来的任务id
taskService.complete("5005");

影响的表:

  • act_hi_actinst

  • act_hi_identitylink

  • act_hi_taskinst

  • act_ru_execution

  • act_ru_identitylink

  • act_ru_task

当流程走完了之后,ru表中的数据都没有了,因为这些表存储正在运行时的数据

流程定义的查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
String processDefinitionKey = "holiday";

RepositoryService repositoryService = ProcessEngines.getDefaultProcessEngine().getRepositoryService();

//得到ProcessDefinitionQuery对象,就相当于一个查询器
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();

//设置条件查询当前所有流程定义 条件流程定义的key=holiday
//orderByProcessDefinitionVersion() 根据流程定义版本号进行排序
List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey(processDefinitionKey)
.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("流程定义的版本号:"+processDefinition.getVersion());
}
删除已经部署的流程定义
1
2
3
4
RepositoryService repositoryService = ProcessEngines.getDefaultProcessEngine().getRepositoryService();

//执行删除流程定义id,参数是流程定义id
repositoryService.deleteDeployment("2501");

影响的表:

  • act_ge_bytearray
  • act_re_deployment
  • act_re_procdef

注意点

  •  当正在执行的这一套流程没有完全审批结束时,此时如果要删除流程定义信息就会失败
    
  •  如果要强制删除,可以使用repositoryService.deleteDeployment("2501",true),参数true代表级联删除,此时会先删除没有完成的流程节点,最后就可以删除流程定义信息,默认false
    
读取act_ge_bytearray中的资源文件保存到磁盘中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//得到ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//得到RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();

//得到查询器ProcessDefinitionQuery
ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();

//设置查询条件
query.processDefinitionKey("holiday");

//执行查询条件,查出流程定义
ProcessDefinition processDefinition = query.singleResult();

//通过流程定义信息得到部署ID
String deploymentId = processDefinition.getDeploymentId();

//通过RepositoryService实现读取图片信息(输入流)
//第一个参数是 部署id,第二个参数是 资源名称
//getResourceName是获取bpmn文件的文件名,getDiagramResourceName是获取png文件资源
InputStream inputStream = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());

//构建输出流
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream("D:\\" + processDefinition.getResourceName());
} catch (FileNotFoundException e) {
e.printStackTrace();
}

//输入流输出流转换 commons-io中的方法
try {
IOUtils.copy(inputStream, outputStream);
outputStream.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
历史数据的查看
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void main(String[] args) {
//的到ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//得到HistoryService
HistoryService service = processEngine.getHistoryService();

//得到HistorcActivitiInstanceQuery
HistoricActivityInstanceQuery query = service.createHistoricActivityInstanceQuery();

//执行查询
query.processInstanceId("5001");
List<HistoricActivityInstance> list = query.orderByHistoricActivityInstanceStartTime().asc().list();

//遍历结果
for (HistoricActivityInstance instance : list) {
System.out.println(instance.getActivityId());
System.out.println(instance.getActivityName());
System.out.println(instance.getProcessDefinitionId());
System.out.println(instance.getProcessInstanceId());
System.out.println("------------------------------------");
}
}
启动流程实例,添加BusinessKey
1
2
3
4
5
6
7
8
9
10
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//获得RuntimeService
RuntimeService service = processEngine.getRuntimeService();

//启动流程实例,同时指定业务标识BusinessKey,本身就是请假单的id
//第一个参数是流程定义的key,第二个参数是业务标识BusinessKey
ProcessInstance processInstance = service.startProcessInstanceByKey("holiday", "1001");

System.out.println(processInstance.getBusinessKey());
全部流程实例挂起与激活
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//得到RepositoryService
RepositoryService service = processEngine.getRepositoryService();

//查询流程定义对象
ProcessDefinition processDefinition = service.createProcessDefinitionQuery()
.processDefinitionKey("holiday")
.singleResult();

//判断当前流程定义的实例是否都为暂停状态
boolean suspended = processDefinition.isSuspended();

if (suspended) {
//激活
service.activateProcessDefinitionById(processDefinition.getId(),true,null);
System.out.println("流程定义->" + processDefinition.getId() + "被激活");
}else {
service.suspendProcessDefinitionById(processDefinition.getId(), true, null);
System.out.println("流程定义->" + processDefinition.getId() + "被挂起");
}
挂起激活单个实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

//得到RuntimeService
RuntimeService service = processEngine.getRuntimeService();

//查询流程实例对象
ProcessInstance processInstance = service.createProcessInstanceQuery()
.processInstanceId("25001").singleResult();

//查看当前实例是否为暂停状态
boolean suspended = processInstance.isSuspended();

String instanceId = processInstance.getId();

if (suspended) {
service.activateProcessInstanceById(instanceId);
System.out.println("实例->"+instanceId+"激活");
}else {
service.suspendProcessInstanceById(instanceId);
System.out.println("实例->"+instanceId+"挂起");
}

如果处理挂起的流程实例抛出异常->ActivitiException: Cannot complete a suspended task

动态设置assignee(BPM图中的assigness设置为${xxx})
1
2
3
4
5
6
7
8
9
10
11
12
13
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

RuntimeService service = processEngine.getRuntimeService();

//设置assignee的取值 用户可以在街面上选取执行人
HashMap<String, Object> map = new HashMap<>();
map.put("assignee0", "a0");
map.put("assignee1", "a1");
map.put("assignee2", "a2");

ProcessInstance processInstance = service.startProcessInstanceByKey("holiday", map);

System.out.println(processInstance.getId());
有条件判断的流程实例(流程变量)

在画bpmn图的时候需要在线路上的Condition中填入条件,例如${holiday.num>3}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService service = processEngine.getRuntimeService();

String key = "holiday2";

Holiday holiday = new Holiday();
holiday.setNum(1f);

HashMap<String, Object> map = new HashMap<>();
map.put("holiday", holiday);

ProcessInstance instance = service.startProcessInstanceByKey(key, map);

System.out.println(instance.getName());
System.out.println(instance.getProcessDefinitionId());
办理时设置流程变量

流程实例的启动没有不添加特别的参数

1
2
3
4
5
6
7
8
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService service = processEngine.getRuntimeService();

String key = "holiday2";
ProcessInstance instance = service.startProcessInstanceByKey(key);

System.out.println(instance.getName());
System.out.println(instance.getProcessDefinitionId());
执行任务时添加参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

TaskService service = processEngine.getTaskService();

//查询当前用户任务
Task task = service.createTaskQuery()
.processDefinitionKey("holiday2")
.taskAssignee("a1")
.singleResult();

Holiday holiday = new Holiday();
holiday.setNum(1f);

HashMap<String, Object> map = new HashMap<>();
map.put("holiday", holiday);

if (task != null) {
//完成任务时设置流程变量
service.complete(task.getId(),map);
System.out.println("任务执行完毕");
return;
}
通过当前流程实例id设置变量

启动流程实例后执行

1
2
3
4
5
6
7
8
9
10
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService service = processEngine.getRuntimeService();

String instanceId = "2501";

Holiday holiday = new Holiday();
holiday.setNum(1f);

//第一个参数:流程实例id。第二个:变量名称。对三个:对应的值
service.setVariable(instanceId,"holiday",holiday);
通过任务id设置变量

和通过当前流程实例id设置变量差不多 ,只是通过不同的service↑

但是如果任务已经结束再设置就会报错

设置局部(Local)变量(以上都为Global)

通过service.setVariableLocal()

设置任务候选人

可以在设置Candidate Users时用逗号隔开候选人

查询候选人的组任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService service = processEngine.getTaskService();

String key = "holiday3";
String candiate = "a3";

List<Task> tasks = service.createTaskQuery()
.processDefinitionKey(key)
.taskCandidateUser(candiate)
.list();

for (Task task : tasks) {
System.out.println(task.getProcessDefinitionId());
System.out.println(task.getId());
System.out.println(task.getName());
System.out.println(task.getAssignee());
}
候选人拾取任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService service = processEngine.getTaskService();

String key = "holiday3";
String candidate = "a3";

Task task = service.createTaskQuery()
.processDefinitionKey(key)
.taskCandidateUser(candidate)
.singleResult();

if (task != null) {
service.claim(task.getId(), candidate);
System.out.println("任务拾取完毕");
}

此时用户已经从候选人变成了任务负责人,就可以使用以前的方法执行任务

候选人归还任务

使用service.setAssignee(taskId,null),将任务负责人设置为空就能达到效果

任务交接(交给其他候选人)

使用service.setAssignee(taskId,anotherCandidate),将任务负责人设置为其他候选人就能达到效果

activiti网关
  • 排他网关:用来在流程中实现决策,当流程执行到这个网关,所有分支都会判断条件是否为true,如果为true则执行,如果有两个为true,也只会选择一个分支执行。如果不使用排他网管,如果有两个分支同时为true,那么两个分支同时执行,就会出问题
    • 在画流程图时,在分支前使用ExclusiveGateway网关节点
    • 默认会走下个节点id更小的分支
  • 并行网关:允许将流程分成多个分支,也可以把多个分支聚集在一起
    • fork分支:并行后的的所有外出顺序流,为每个顺序流都创建一个并发分支
    • join汇聚:所有到达并行网关,在此等待的进入分支,直到所有进入顺序流的分支都到达后,流程就会通过汇聚网关
    • 与其它网关的主要区别:并行网关不会解析任务。即使顺序流中定义了条件,也会被忽略
  • 包含网关:排他和并行的结合体,其中符合条件的分支就会并行执行

与Spring的整合

POM文件就用一开始POM文件内容

spring-activiti.xml文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.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/activiti"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<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"/>
<!-- 数据库生成策略 -->
<property name="databaseSchemaUpdate" value="true"/>
</bean>

<!-- 流程引擎、通过工厂方式创建出ProcessEngine对象-->
<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(* cn.dsh.springactiviti.service.impl.*.*(..))"/>
</aop:config>

</beans>

与SpringBoot的整合

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.activiti.dependencies</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>${activiti-dependencies.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>

<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</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-security</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

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

SecurityUtil(可以从官网示例上复制)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@Component
public class SecurityUtil {

@Autowired
private UserDetailsService userDetailsService;

public void logInAs(String username) {

UserDetails user = userDetailsService.loadUserByUsername(username);
if (user == null) {
throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
}

SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getAuthorities();
}

@Override
public Object getCredentials() {
return user.getPassword();
}

@Override
public Object getDetails() {
return user;
}

@Override
public Object getPrincipal() {
return user;
}

@Override
public boolean isAuthenticated() {
return true;
}

@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {

}

@Override
public String getName() {
return user.getUsername();
}
}));
org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
}
}

DemoApplicationConfiguration(可以官网复制)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@Configuration
@EnableWebSecurity
public class DemoApplicationConfiguration extends WebSecurityConfigurerAdapter {

private Logger logger = LoggerFactory.getLogger(DemoApplicationConfiguration.class);

@Override
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService());
}

@Bean
public UserDetailsService myUserDetailsService() {

InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();

String[][] usersGroupsAndRoles = {
{"salaboy", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"ryandawsonuk", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"erdemedeiros", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
{"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
{"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;
}


@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();


}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

applicaion.yml

1
2
3
4
5
6
7
8
9
10
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/activiti?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=CTT&characterEncoding=UTF-8
driver-class-name: com.mysql.cj.jdbc.Driver
activiti:
#开启历史信息
db-history-used: true
history-level: full
部署流程定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Autowired
private ProcessRuntime processRuntime;

@Autowired
private TaskRuntime taskRuntime;

@Autowired
private SecurityUtil securityUtil;

/**
* 流程定义信息的查看
* 流程部署工作在activiti7和springboot整合后,会自动部署,但是需要放在resource/processes目录下
*/
@Test
public void testDefinition() {
//不加就没有访问权限,springsecurity认证
securityUtil.logInAs("salaboy");

//分页查询出流程定义信息
Page<ProcessDefinition> page = processRuntime.processDefinitions(Pageable.of(0, 10));

//查看已部署的流程个数
System.out.println(page.getTotalItems());

for (ProcessDefinition definition : page.getContent()) {
System.out.println(definition);
}
}
启动流程实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 启动流程实例
*/
@Test
public void testStartInstance() {
securityUtil.logInAs("salaboy");

//启动实例
ProcessInstance instance = processRuntime.start(ProcessPayloadBuilder
.start()
.withProcessDefinitionKey("team01")
.build());

System.out.println(instance.getId());
}
执行任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 查询任务,并完成任务
*/
@Test
public void testTask() {
//指定用户认证信息
securityUtil.logInAs("erdemedeiros");

Page<Task> taskPage= taskRuntime.tasks(Pageable.of(0, 10));
if (taskPage.getTotalItems() > 0) {
for (Task task : taskPage.getContent()) {

System.out.println("任务->"+task);

//拾取任务 必须是activitiTeam组中的用户 画图的时候设置的组
taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(task.getId()).build());

//执行任务
taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()).build());
}
}

//再次查询
taskPage= taskRuntime.tasks(Pageable.of(0, 10));
if (taskPage.getTotalItems() > 0) {
for (Task task : taskPage.getContent()) {
System.out.println("任务->"+task);
}
}

}