文章目录
- activiti使用详解
- 快速开始
- 在项目中添加如下依赖项
- 修改application.yml配置文件和启动类
- 在resources目录下新建processes目录并添加如下流程文件task_process.bpmn
- 新建如下类
- 编写测试类
- activiti核心api
- 流程引擎及服务
- 流程存储服务 RepositoryService
- 流程运行控制服务 RuntimeService
- 启动流程变量管理
- 流程实例与执行流
- 流程触发
- api
- 任务管理服务 TaskService
- TaskService对Task管理与流程控制
- TaskService设置Task权限信息
- TaskService设置Task附加信息
- 身份管理服务 IdentityService
- 表单服务管理 FormService
- 历史管理服务 HistoryService
- HistoryService构建历史查询对象
- HistoryService删除历史操作
- 其他管理服务
- ManagementService
- Job任务查询
- 数据库相关操作
- 异常策略 ActivitiEXception
- bpmn文件详解
- bpmn各节点详解
- serviceTask使用的多种方式
- 执行监听器( Execution listener)
- Activiti 23张表
- 23张表概述
- 23张表详解
- 二进制数据表(act_ge_bytearray)
- 属性数据表(act_ge_property)
- 历史节点表(act_hi_actinst)
- 历史附件表( act_hi_attachment )
- 历史意见表( act_hi_comment )
- 历史详情表( act_hi_detail )
- 历史流程人员表( act_ru_identitylink )
- 历史流程实例表(act_hi_procinst)
- 历史任务实例表( act_hi_taskinst )
- 历史变量表( act_hi_varinst )
- 用户组信息表( act_id_group )
- 用户扩展信息表( act_id_info )
- 用户与分组对应信息表( act_id_membership )
- 用户信息表( act_id_user )
- 部署信息表( 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 )
activiti使用详解
快速开始
在项目中添加如下依赖项
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-spring-boot-starter-basicartifactId>
<version>6.0.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
- 注意:如果项目中使用的mybatis并且使用的tk-mybatis需要做如下修改
<dependency>
<groupId>tk.mybatisgroupId>
<artifactId>mapper-spring-boot-starterartifactId>
<version>2.0.4version>
<exclusions>
<exclusion>
<artifactId>persistence-apiartifactId>
<groupId>javax.persistencegroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
- 查看一下JpaProcessEngineAutoConfiguration类,部分代码如下:
public class JpaProcessEngineAutoConfiguration {
public JpaProcessEngineAutoConfiguration() {
}
@Configuration
@ConditionalOnClass(
name = {"javax.persistence.EntityManagerFactory"}
)
@EnableConfigurationProperties({ActivitiProperties.class})
public static class JpaConfiguration extends AbstractProcessEngineAutoConfiguration {
public JpaConfiguration() {
}
}
}
- 可以看到EntityManagerFactory是被@ConditionlOnClass所注解的。而EntityManagerFactory是来自于JPA相关的接口。其实这里是Activiti所做的判断,如果项目使用了JPA,那走JPA,如果没有,则走Mybatis。所以只引入Mybatis和Activiti的话项目不会报错,那为什么引入了Mapper就会报错呢?继续看mapper的源码就能知道原因,其实mapper并没有实现EntityManagerFactory接口,而是自己写了一套,而在Activiti中则认为当前项目使用的是JPA,找不到EntityManagerFactory的实现类。所以报错。解决方法就是在mapper中移除对persistence-api依赖,在activiti中加上jpa的依赖。这样的话,项目启动不会报错,并且能正常使用tkmybatis,省去了公共的增删改查代码。
修改application.yml配置文件和启动类
spring:
activiti:
database-schema-update: true
history-level: full
check-process-definitions: true
process-definition-location-prefix: classpath:/processes/
排除org.activiti.spring.boot.SecurityAutoConfiguration.class
类
package com.zzvcom.task.center;
import org.activiti.spring.boot.SecurityAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(exclude = {
SecurityAutoConfiguration.class})
public class CenterApplication {
public static void main(String[] args) {
SpringApplication.run(CenterApplication.class, args);
}
}
在resources目录下新建processes目录并添加如下流程文件task_process.bpmn
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 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" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1572328617189" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="task_process_001" isClosed="false" isExecutable="true" name="试题审核流程" processType="None">
<startEvent id="_2" name="StartEvent"/>
<userTask activiti:exclusive="true" id="_3" name="试卷导入"/>
<sequenceFlow id="_4" sourceRef="_2" targetRef="_3"/>
<userTask activiti:exclusive="true" id="_5" name="试题审核"/>
<exclusiveGateway gatewayDirection="Unspecified" id="_7" name="试题维度审核网关"/>
<sequenceFlow id="_8" sourceRef="_5" targetRef="_7"/>
<userTask activiti:exclusive="true" id="_9" name="试题终审"/>
<endEvent id="_13" name="EndEvent"/>
<sequenceFlow id="_14" sourceRef="_9" targetRef="_13"/>
<sequenceFlow id="_10" name="审核通过" sourceRef="_7" targetRef="_9">
<conditionExpression xsi:type="tFormalExpression">conditionExpression>
sequenceFlow>
<sequenceFlow id="_11" name="驳回" sourceRef="_7" targetRef="_3">
<conditionExpression xsi:type="tFormalExpression">conditionExpression>
sequenceFlow>
<serviceTask activiti:class="com.zzvcom.task.center.task.ServiceTask" activiti:exclusive="true" id="_15" name="试题重复检查"/>
<sequenceFlow id="_16" sourceRef="_3" targetRef="_15"/>
<userTask activiti:exclusive="true" id="_6" name="试题重复仲裁"/>
<exclusiveGateway gatewayDirection="Unspecified" id="_12" name="试题重复检查网关"/>
<sequenceFlow id="_17" sourceRef="_15" targetRef="_12"/>
<sequenceFlow id="_19" sourceRef="_12" targetRef="_5">
<conditionExpression xsi:type="tFormalExpression">conditionExpression>
sequenceFlow>
<sequenceFlow id="_20" sourceRef="_12" targetRef="_6">
<conditionExpression xsi:type="tFormalExpression">conditionExpression>
sequenceFlow>
<sequenceFlow id="_21" sourceRef="_6" targetRef="_5"/>
process>
<bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
<bpmndi:BPMNPlane bpmnElement="task_process_001">
<bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
<omgdc:Bounds height="32.0" width="32.0" x="55.0" y="-5.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
<omgdc:Bounds height="55.0" width="85.0" x="30.0" y="85.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
<omgdc:Bounds height="55.0" width="85.0" x="40.0" y="465.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7" isMarkerVisible="false">
<omgdc:Bounds height="32.0" width="32.0" x="260.0" y="470.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_9" id="Shape-_9">
<omgdc:Bounds height="55.0" width="85.0" x="35.0" y="565.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_13" id="Shape-_13">
<omgdc:Bounds height="32.0" width="32.0" x="55.0" y="680.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_15" id="Shape-_15">
<omgdc:Bounds height="55.0" width="85.0" x="35.0" y="185.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
<omgdc:Bounds height="55.0" width="85.0" x="350.0" y="270.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_12" id="Shape-_12" isMarkerVisible="false">
<omgdc:Bounds height="32.0" width="32.0" x="65.0" y="300.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_14" id="BPMNEdge__14" sourceElement="_9" targetElement="_13">
<omgdi:waypoint x="71.0" y="620.0"/>
<omgdi:waypoint x="71.0" y="680.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_17" id="BPMNEdge__17" sourceElement="_15" targetElement="_12">
<omgdi:waypoint x="81.0" y="240.0"/>
<omgdi:waypoint x="81.0" y="300.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_16" id="BPMNEdge__16" sourceElement="_3" targetElement="_15">
<omgdi:waypoint x="75.0" y="140.0"/>
<omgdi:waypoint x="75.0" y="185.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_19" id="BPMNEdge__19" sourceElement="_12" targetElement="_5">
<omgdi:waypoint x="81.0" y="332.0"/>
<omgdi:waypoint x="81.0" y="465.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_4" id="BPMNEdge__4" sourceElement="_2" targetElement="_3">
<omgdi:waypoint x="71.0" y="27.0"/>
<omgdi:waypoint x="71.0" y="85.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_5" targetElement="_7">
<omgdi:waypoint x="125.0" y="492.5"/>
<omgdi:waypoint x="260.0" y="486.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_20" id="BPMNEdge__20" sourceElement="_12" targetElement="_6">
<omgdi:waypoint x="97.0" y="316.0"/>
<omgdi:waypoint x="350.0" y="297.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="_7" targetElement="_3">
<omgdi:waypoint x="275.0" y="471.0"/>
<omgdi:waypoint x="275.0" y="220.0"/>
<omgdi:waypoint x="115.0" y="112.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_7" targetElement="_9">
<omgdi:waypoint x="275.0" y="501.0"/>
<omgdi:waypoint x="275.0" y="545.0"/>
<omgdi:waypoint x="120.0" y="592.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_21" id="BPMNEdge__21" sourceElement="_6" targetElement="_5">
<omgdi:waypoint x="350.0" y="275.0"/>
<omgdi:waypoint x="0.0" y="275.0"/>
<omgdi:waypoint x="40.0" y="492.5"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
bpmndi:BPMNLabel>
bpmndi:BPMNEdge>
bpmndi:BPMNPlane>
bpmndi:BPMNDiagram>
definitions>
新建如下类
package com.zzvcom.task.center.task;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;
public class ServiceTask implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
System.out.println("serviceTask已执行");
execution.setVariable("repeat",false);
}
}
package com.zzvcom.task.center.service;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Map;
@Service
public class TaskProcessService {
@Resource
private RuntimeService runtimeService;
@Resource
private IdentityService identityService;
@Resource
private TaskService taskService;
@Resource
private HistoryService historyService;
private static final String PROCESS_DEFINE_KEY = "task_process_001";
public void startTask(String id) {
Task currentTask = query(id);
taskService.complete(currentTask.getId());
}
public void execTask(String processId){
execTask(processId,null);
}
public void execTask(String id,Map<String, Object> variables) {
Task currentTask = query(id);
taskService.complete(currentTask.getId(),variables);
}
public String createTask() {
ProcessInstance vacationInstance = runtimeService.startProcessInstanceByKey(PROCESS_DEFINE_KEY);
return vacationInstance.getId();
}
public Task query(String id) {
Task currentTask = taskService.createTaskQuery().processInstanceId(id).singleResult();
return currentTask;
}
public Task query(String id,String name){
Task currentTask = taskService.createTaskQuery().processInstanceId(id).taskName(name).singleResult();
return currentTask;
}
}
编写测试类
package com.zzvcom.task.center;
import com.zzvcom.task.center.service.TaskProcessService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TaskProcessTest extends CenterApplicationTests {
@Autowired
private TaskProcessService taskProcessService;
@Resource
private HistoryService historyService;
@Test
public void test001(){
System.out.println("创建一个流程");
String processId = taskProcessService.createTask();
System.out.println("流程id:"+processId);
System.out.println("试题导入task");
taskName(processId);
Map<String,Object> variables = new HashMap<>();
System.out.println("提交流程试题导入task并进行试题重复检查");
variables.put("firstSubmit",true);
variables.put("repeatFlag",true);
taskProcessService.execTask(processId,variables);
taskName(processId);
System.out.println("提交试题重复仲裁task");
taskProcessService.execTask(processId);
taskName(processId);
System.out.println("提交试题审核task-审核不通过进行驳回");
variables.put("adopt",false);
taskProcessService.execTask(processId,variables);
taskName(processId);
System.out.println("驳回后再次提交试题导入task,不进行试题重复检查");
variables.put("firstSubmit",false);
taskProcessService.execTask(processId,variables);
taskName(processId);
System.out.println("提交试题审核task,审核通过");
variables.put("adopt",true);
taskProcessService.execTask(processId,variables);
taskName(processId);
System.out.println("提交试题终审task");
taskProcessService.execTask(processId);
System.out.println("任务结束-输出流程记录--------------------------");
HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().processInstanceId(processId);
List<HistoricTaskInstance> list = historicTaskInstanceQuery.finished().list();
for (HistoricTaskInstance hti : list) {
System.out.println(hti.getId()+"==="+hti.getName());
}
}
@Test
public void test002(){
System.out.println("创建一个流程");
String processId = taskProcessService.createTask();
System.out.println("流程id:"+processId);
System.out.println("试题导入task");
taskName(processId);
Map<String,Object> variables = new HashMap<>();
System.out.println("提交流程试题导入task并进行试题重复检查");
variables.put("firstSubmit",true);
taskProcessService.execTask(processId,variables);
taskName(processId);
System.out.println("提交试题审核task-审核不通过进行驳回");
variables.put("adopt",false);
taskProcessService.execTask(processId,variables);
taskName(processId);
System.out.println("驳回后再次提交试题导入task,不进行试题重复检查");
variables.put("firstSubmit",false);
taskProcessService.execTask(processId,variables);
taskName(processId);
System.out.println("提交试题审核task,审核通过");
variables.put("adopt",true);
taskProcessService.execTask(processId,variables);
taskName(processId);
System.out.println("提交试题终审task");
taskProcessService.execTask(processId);
System.out.println("任务结束-输出流程记录--------------------------");
HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().processInstanceId(processId);
List<HistoricTaskInstance> list = historicTaskInstanceQuery.finished().list();
for (HistoricTaskInstance hti : list) {
System.out.println(hti.getId()+"==="+hti.getName());
}
}
@Test
public void test003(){
System.out.println("创建一个流程");
String processId = taskProcessService.createTask();
System.out.println("流程id:"+processId);
System.out.println("试题导入task");
taskName(processId);
Map<String,Object> variables = new HashMap<>();
System.out.println("提交流程试题导入task并进行试题重复检查");
variables.put("firstSubmit",true);
variables.put("repeatFlag",true);
taskProcessService.execTask(processId,variables);
taskName(processId);
System.out.println("提交试题重复仲裁task");
taskProcessService.execTask(processId);
taskName(processId);
System.out.println("提交试题审核task,审核通过");
variables.put("adopt",true);
taskProcessService.execTask(processId,variables);
taskName(processId);
System.out.println("提交试题终审task");
taskProcessService.execTask(processId);
System.out.println("任务结束-输出流程记录--------------------------");
HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().processInstanceId(processId);
List<HistoricTaskInstance> list = historicTaskInstanceQuery.finished().list();
for (HistoricTaskInstance hti : list) {
System.out.println(hti.getId()+"==="+hti.getName());
}
}
public void taskName(String taskId){
Task query = taskProcessService.query(taskId);
System.out.println("task名称:"+query.getName());
}
}
activiti核心api
流程引擎及服务
- RepositoryService 流程仓库Service,可以管理流程仓库例如部署删除读取流程资源
- RuntimeService 运行时Service可以处理所有运行状态的流程实例流程控制(开始,暂停,挂起等)
- TaskService 任务Service用于管理、查询任务,例如签收、办理、指派等
- IdentitiServicec 身份Service可以管理查询用户、组之间的关系
- FormService 表单Service用于读取和流程、任务相关的表单数据
- HistoryService 历史Service用于查询所有的历史数据
- ManagementService 引擎管理Service,和具体业务无关,主要查询引擎配置,数据库作业
- DynamicBpmService 动态bpm服务
流程存储服务 RepositoryService
- 管理流程定义文件xml及静态资源服务
- 对流程定义文件对暂停激活
- 流程定义启动权限管理
- 部署文件构造器DeploymentBuilder
- 部署文件查询器DeploymentQuery
- 流程定义文件查询对象ProcessDefinitionQuery
api
方法 |
描述 |
库表字段 |
repositoryService.createDeployment().addClasspathResource(“参数”) .deploy() |
部署流程 resources文件下面的xml流程文件 |
省略 |
repositoryService.createDeploymentQuery().list() |
查询所有部署 |
省略 |
repositoryService.createProcessDefinitionQuery().list() |
查询所有部署的流程 |
省略 |
repositoryService.suspendProcessDefinitionById(id)或ByKey |
根据流程id挂起流程 |
修改表ACT_RE_PROCDEF字段SUSPENSION_STATE_:1激活 2挂起 |
repositoryService.activateProcessDefinitionById(id)或ByKey |
根据流程id激活流程 |
修改表ACT_RE_PROCDEF字段SUSPENSION_STATE_:1激活 2挂起 |
repositoryService.addCandidateStarterUser(流程id,用户id) |
添加流程与用户关系 |
操作ACT_RU_IDENTITYLINK表 |
repositoryService.deleteCandidateStarterGroup(流程id,用户组id) |
添加流程与用户组关系 |
操作ACT_RU_IDENTITYLINK表 |
repositoryService.deleteCandidateStarterUser(流程id,用户id) |
删除流程与用户关系 |
操作ACT_RU_IDENTITYLINK表 |
repositoryService.deleteCandidateStarterGroup(流程id,用户组id) |
删除流程与用户组关系 |
操作ACT_RU_IDENTITYLINK表 |
repositoryService.getIdentityLinksForProcessDefinition(流程id) |
查询流程对应用户跟组关系 |
查询ACT_RU_IDENTITYLINK表 |
流程运行控制服务 RuntimeService
- 启动流程及对流程数据对控制
- 流程实例(ProcessInstance)与执行流(Execution)查询
- 触发流程操作、接收消息和信号
启动流程变量管理
- 启动流程的常用方式(id,key,message)
- 启动流程可选参数(businesskey,variables,tenantId)
- 变量(variables)的设置和获取
流程实例与执行流
- 流程实例(ProcessInstance)表示一次工作流业务的数据实体
- 执行流(Execution)表示流程实例中具体的执行路径
- 流程实例接口继承与执行流
流程触发
- 使用trigger触发ReceiveTask节点
- 触发信号捕获事件signalEvenReceived
- 触发消息捕获事件messageEventReceived
api
方法 |
描述 |
runtimeService.startProcessInstanceByKey(String processDefinitionKey, Map variables) |
根据部署流程key启动一个流程 |
runtimeService.startProcessInstanceById(String processDefinitionId, Map variables) |
根据部署流程id启动一个流程 |
runtimeService.createProcessInstanceBuilder().businessKey(“businessKey001”) .processDefinitionKey(String processDefinitionKey).variables( Map variables) .start() |
根据processInstanceBuilder启动流程 |
runtimeService.getVariables(processInstance.getId()) |
根据流程实例id获取传参 |
runtimeService.setVariable(processInstance.getId(),“key3”,“value3”) |
新增或修改参数 |
runtimeService.createProcessInstanceQuery().processInstanceId(processInstance.getId()) |
查询流程实例 |
runtimeService.createExecutionQuery() |
获取流程执行对象 |
任务管理服务 TaskService
- 对用户任务(UserTask)管理和流程控制
- 设置用户任务(UserTask)对权限信息(拥有者,候选人,办理人)
- 针对用户任务添加任务附件、任务;评价和事件记录
TaskService对Task管理与流程控制
- Task对象对创建,删除
- 查询Task,并驱动Task节点完成执行
- Task相关参数变量(variable)设置
方法 |
描述 |
taskService.createTaskQuery().list() |
查询所有任务 |
taskService.setVariable(“任务id”,“键”,“值”) |
设置普通变量 |
taskService.setVariableLocal(“任务id”,“键”,“值”) |
设置本地变量 |
taskService.getVariables(“任务id”) |
获取普通变量 |
taskService.getVariablesLocal((“任务id”) |
获取本地变量 |
runtimeService.getVariables(task.getExecutionId()) |
通过流获取变量 |
taskService.complete(“任务id”,“传值Map”) |
到下一个节点 |
TaskService设置Task权限信息
- 候选用户(candidateUser)和候选组(candidateGroup)
- 指定拥有人(Owner)和办理人(Assignee)
- 通过claim设置办理人
方法 |
描述 |
taskService.setOwner(“taskId”,“user”) |
设置流程发起人 |
taskService.claim("“taskId”",“user”) |
指定代办人 |
taskService.addCandidateUser(“user”) |
添加候选人 |
taskService.addCandidateGroup(“group”) |
添加候选组 |
taskService.createTaskQuery().taskCandidateUser(“user”).taskUnassigned().list() |
查询候选人列表有user但是没指定代办人任务 |
taskService.createTaskQuery().taskCandidateUser(“user”).taskUnassigned().list() |
查询候选人列表有我但是没指定代办人任务 |
taskService.createTaskQuery().taskAssignee(“user”).list() |
查询代办人为user的任务 |
taskService.getIdentityLinksForTask(“taskId”) |
查询任务与人员之间的关系 |
TaskService设置Task附加信息
- 任务附件(Attachment)创建与查询
- 任务评价(Comment)创建与查询
方法 |
描述 |
taskService.createAttachment(“类型”,“任务id”,“流程Id”,“附件名称”,“附件描述”,"流或者url) |
上传附件 |
taskService.getTaskAttachments(“任务id”) |
获取附件 |
taskService.addComment(“任务id”,“流程id”,“批注1”) |
添加审批批注 |
taskService.getTaskComments(“任务id”) |
查询审批批注 |
taskService.getTaskEvents(“任务id”) |
查询任务日志记录 |
身份管理服务 IdentityService
- 管理用户(User)
- 管理用户组(Group)
- 用户与用户组关系(Membership)
方法 |
描述 |
dentityService.newUser(“userid”) |
创建一个用户 |
identityService.newGroup(“groupid”) |
创建一个组 |
identityService.saveUser(user) |
保存或者更新用户 |
identityService.saveGroup(group) |
保存或者更新组 |
identityService.createUserQuery() |
查询用户 |
identityService.createGroupQuery() |
查询组 |
表单服务管理 FormService
- 解析流程定义中表单项的配置
- 提交表单的方式驱动用户节点流转
- 获取自定义外部表单key
方法 |
描述 |
formService.getStartFormKey(processDefinition.getId()) |
部署流程的id获取表单key |
formService.getStartFormData(processDefinition.getId()).getFormProperties() |
获取开始节点表单内容 |
formService.getStartFormData(processDefinition.getId()).getFormProperties() |
获取开始节点表单内容 |
formService.submitStartFormData(processDefinition.getId(), “传值参数”) |
通过formservice启动流程 |
formService.submitTaskFormData(“taskId”,“传参数”) |
formService.submitTaskFormData(“taskId”,“传参数”) |
formService.getTaskFormData(“taskId”) |
通过taskid获取task节点表单内容 |
历史管理服务 HistoryService
- 管理流程实例结束后的历史数据
- 构建历史数据查询对象
- 根据流程实例id删除流程历史数据
历史数据实体 |
描述 |
Historicprocessinstance |
历史流程实例实体类 |
Historicvariablelnstance |
流程或任务变量值的实体类 |
Historicactivityinstance |
单个活动节点执行的信息 |
Historictaskinstance |
用户任务实例的的信息 |
Historicdetail |
历史流程活动任务详细信息 |
HistoryService构建历史查询对象
- create[历史数据实体]Query
- createNative[历史数据实体]Query | 通过原生sql查询
- createProcessInstanceHistoryLogQuery | 查询一个流程实例的所有其他数据
HistoryService删除历史操作
- deleteHistoricProcessInstance | 删除历史流程实例及联删除其他信息
- deleteHistoricTaskInstance | 删除历史的task实例
方法 |
描述 |
historyService.createHistoricProcessInstanceQuery() |
查询流程实例变量 |
historyService.createHistoricActivityInstanceQuery() |
查询活动节点 |
historyService.createHistoricTaskInstanceQuery() |
查询任务实例 |
historyService.createHistoricVariableInstanceQuery() |
查询流程任务变量 |
historyService.createHistoricDetailQuery() |
历史任务流程活动详细信息 |
historyService.createProcessInstanceHistoryLogQuery(“流程实例id”) |
查询一个流程实例的所有其他数据 |
historyService.deleteHistoricProcessInstance(“流程实例id”) |
删除历史流程实例 |
historyService.deleteHistoricTaskInstance(“taskid”) |
删除历史任务 |
其他管理服务
- 管理服务ManagementService
- 动态流程定义服务DynamicBpmnService
ManagementService
- job任务管理
- 数据库相关通用操作
- 执行流程引擎命令(Command)
Job任务查询
- JobQuery 查询一般工作
- TimerJobQuery 查询定时工作
- SuspendedJobQuery 查询中断工作
- DeadLetterJobQuery 查询无法执行的工作
方法 |
描述 |
managementService.createTimerJobQuery() |
查询定时工作 |
managementService.createJobQuery() |
查询一般工作 |
managementService.createSuspendedJobQuery() |
查询中断工作 |
managementService.createDeadLetterJobQuery() |
查询无法执行的工作 |
数据库相关操作
- 查询表结构元数据(TableMetaData)
- 通用查询(TablePageQuery)
- 执行自定义Sql查询(executeCustomSql)
方法 |
描述 |
managementService.createTablePageQuery().tableName(managementService.getTableName(class)) |
查询实体到所有数据 |
managementService.executeCustomSql() |
自定义sql查 |
异常策略 ActivitiEXception
- ActivitiWrongDbException 引擎与数据库版本不匹配
- ActivitiOptimisticLockingException 并发导致乐观锁异常
- ActivitiClassLoadingException 加载类异常
- ActivitiObjectNotFoundException 操作对象不存在
- ActivitilllegalArgumentException 非法的参数
- ActivitiTaskAlreadyClaimedException 任务被重新声明代理人
- BpmnError 定义业务异常控制流程
bpmn文件详解
bpmn各节点详解
- bpmn文件是activiti配置流程定义的文件,一般一个bpmn文件定义一个流程,文件为xml格式,各种元素级别如下:
<definitions>
<process>
<startEvent>startEvent>
<endEvent>endEvent>
<userTask>
<extensionElements>
<activiti:taskListener>activiti:taskListener>
extensionElements>
userTask>
<scriptTask/>
<manualTask/>
<receiveTask/>
<serviceTask/>
<businessRuleTask/>
<exclusiveGateway/>
<parallelGateway/>
<sequenceFlow>
<conditionExpression>conditionExpression>
sequenceFlow>
<subProcess>subProcess>
<boundaryEvent/>boundaryEvent>
process>
<bpmndi:BPMNDiagram>
<bpmndi:BPMNPlane>
<bpmndi:BPMNShape>
<omgdc:Bounds>omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape>
<omgdc:Bounds>omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape>
<omgdc:Bounds>omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape>
<omgdc:Bounds>omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNEdge>
<omgdi:waypoint>omgdi:waypoint>
<omgdi:waypoint>omgdi:waypoint>
bpmndi:BPMNEdge>
bpmndi:BPMNPlane>
bpmndi:BPMNDiagram>
definitions>
- process: 流程定义根元素,代表了一个流程定义的开始,属性如下
属性名 |
含义 |
id |
流程唯一id,启动流程时需要 |
isExecutable |
流程是否可执行 |
name |
流程名称 |
type |
流程类型 |
isClosed |
流程是否已关闭,关闭不能执行 |
- startEvent: 流程启动事件,一个process只能有一个,且必须为流程起始元素
属性名 |
含义 |
id |
启动节点id |
name |
启动节点名称 |
- endEvent: 流程结束事件,一个process只能有一个,且必须为流程结束元素
属性名 |
含义 |
id |
结束节点id |
name |
节点名称 |
- userTask: 流程中间用户任务,夹在startEvent与endEvent之间的节点
属性名 |
含义 |
id |
任务id,使用id操作任务 |
name |
任务名称 |
activiti:assignee |
任务所属用户,只能指定用户完成这个任务,即任务办理人 |
activiti:candidateUsers |
多个任务办理人 |
activiti:candidateGroups |
任务处理人候选组,处理人必须在这个组内 |
activiti:exclusive |
独家的,好像是在排它性网关中使用,意思应该是在有并行分支情况下,只会走其中一条 |
activiti:dueDate |
设置用户任务到期日期 |
activiti:priority |
用户任务优先级,0-100 |
- extensionElements: userTask的子元素,用于扩展元素
- activiti:taskListener: 扩展元素之一,用于监听某个任务的运行
属性名 |
含义 |
event |
监听的任务事件名,create、assignment(分配任务)、complete |
class |
任务监听器类,需要实现TaskListener |
- event (required): 事件类型.。支持的类型有:
- create: 任务被创建,并且所有的属性都被设置好后。
- assignment: 任务被委派给某人后.。注意: 当流程执行到达一个userTask时,会先触发一个assignment事件,再触发create事件。
- complete:在任务完成后,且被从运行时数据(runtime data)中删除前触发。
- delete: 在任务将要被删除之前发生。注意,当任务通过completeTask完成任务时,它也会被执行。
<userTask id="myTask" name="My Task" >
<extensionElements>
<activiti:taskListener event="create" class="org.activiti.MyTaskCreateListener" />
extensionElements>
userTask>
public class MyTaskCreateListener implements TaskListener {
public void notify(DelegateTask delegateTask) {
}
}
- sequenceFlow: 顺序流分为两种:标准顺序流 条件顺序流,其实就是连接两个节点的一条线
属性名 |
含义 |
id |
顺序流id |
sourceRef |
连线的起始节点id,即接近startEvent的节点 |
targetRef |
连线结束节点id,即接近endEvent的节点 |
-
conditionExpression: sequenceFlow子元素,根据表达式确定是否执行这一顺序流,一条顺序流只能联系两个节点。如果需要表达式判断,有多条顺序流连接了同一开始节点,一般这样的开始节点都是网关
|属性名|含义|
|—|---|
|xsi:type|含义不知道,值为tFormalExpression|
|子元素|表达式,${days <= 3}|
-
exclusiveGateway: 排它性网关,即多个sequenceFlow以网关节点开始时,只根据条件执行其中一条流,其他流不再判断。虽然与userTask同属于节点,但是其不作为任务执行。
属性名 |
含义 |
id |
节点id |
name |
节点名称 |
gatewayDirection |
网关方向,Unspecified |
- receiveTask: 接收任务(ReceiveTask)即等待任务,接收任务是一个简单任务,它会等待对应消息的到达。当前,官方只实现了这个任务的java语义。 当流程达到接收任务,流程状态会保存到数据库中。在任务创建后,意味着流程会进入等待状态,直到引擎接收了一个特定的消息, 这会触发流程穿过接收任务继续执行。
- manualTask: 手工任务就是一个自动执行的过程。手动任务几乎不在程序中做什么事情,只是在流程的历史中留下一点痕迹,表明流程是走过某些节点的。而且这个任务是无法用taskservice查询到的。
- mailTask: 邮件task,用于发送邮件
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-emailartifactId>
<version>1.5version>
dependency>
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.2version>
dependency>
- 修改application.yml,这里以网易企业邮箱为例
spring:
activiti:
mail-server-host: smtphz.qiye.163.com
mail-server-port: 994
mail-server-user-name: ***@zzvcom.com
mail-server-password:
mail-server-use-ssl: true
<serviceTask id="sid-A360E361-0D09-460E-9F4D-3A97DD7E3D51" name="发送邮件" activiti:type="mail">
<extensionElements>
<activiti:field name="to">
<activiti:string>activiti:string>
activiti:field>
<activiti:field name="from">
<activiti:string>activiti:string>
activiti:field>
<activiti:field name="subject">
<activiti:string>activiti:string>
activiti:field>
<activiti:field name="text">
<activiti:string>activiti:string>
activiti:field>
<activiti:field name="html">
<activiti:string>activiti:string>
activiti:field>
<activiti:field name="charset">
<activiti:string>activiti:string>
activiti:field>
extensionElements>
serviceTask>
Property |
Required? |
Description |
mailServerHost |
no |
The hostname of your mail server (e.g. mail.mycorp.com). Default is localhost |
mailServerPort |
yes, if not on the default port |
The port for SMTP traffic on the mail server. The default is 25 |
mailServerDefaultFrom |
no |
The default e-mail address of the sender of e-mails, when none is provided by the user. By default this is [email protected] |
mailServerUsername |
if applicable for your server |
Some mail servers require credentials for sending e-mail. By default not set. |
mailServerPassword |
if applicable for your server |
Some mail servers require credentials for sending e-mail. By default not set. |
mailServerUseSSL |
if applicable for your server |
Some mail servers require ssl communication. By default set to false. |
mailServerUseTLS |
if applicable for your server |
Some mail servers (for instance gmail) require TLS communication. By default set to false. |
- The Email task is configured by field injection. All the values for these properties can contain EL expression, which are resolved at runtime during process execution. Following properties can be set:
Property |
Required? |
Description |
to |
yes |
The recipients if the e-mail. Multiple recipients are defined in a comma-separated list |
from |
no |
The sender e-mail address. If not provided, the default configured from address is used. |
subject |
no |
The subject of the e-mail. |
cc |
no |
The cc’s of the e-mail. Multiple recipients are defined in a comma-separated list |
bcc |
no |
The bcc’s of the e-mail. Multiple recipients are defined in a comma-separated list |
charset |
no |
Allows to change the charset of the email, which is necessary for many non-English languages. |
html |
no |
A piece of HTML that is the content of the e-mail. |
text |
no |
The content of the e-mail, in case one needs to send plain none-rich e-mails. Can be used in combination with html, for e-mail clients that don’t support rich content. The client will then fall back to this text-only alternative. |
htmlVar |
no |
The name of a process variable that holds the HTML that is the content of the e-mail. The key difference between this and html is that this content will have expressions replaced before being sent by the mail task. |
textVar |
no |
The name of a process variable that holds the plain text content of the e-mail. The key difference between this and html is that this content will have expressions replaced before being sent by the mail task. |
ignoreException |
no |
Whether an failure when handling the e-mail throws an ActivitiException. By default this is set to false. |
exceptionVariableName |
no |
When email handling does not throw an exception since ignoreException = true a variable with the given name is used to hold a failure message |
- The following XML snippet shows an example of using the Email Task.
<serviceTask id="sendMail" activiti:type="mail">
<extensionElements>
<activiti:field name="from" stringValue="[email protected]" />
<activiti:field name="to" expression="${recipient}" />
<activiti:field name="subject" expression="Your order ${orderId} has been shipped" />
<activiti:field name="html">
<activiti:expression>
Hello ${male ? 'Mr.' : 'Mrs.' } ${recipientName},
As of ${now}, your order has been processed and shipped.
Kind regards,
TheCompany.