首先创建springboot项目,可以直接在IDEA上File
-> New
-> Project
-> Spring Initializr
-> Next
即可创建简单的springboot项目。
项目前提:
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-spring-boot-starter-basicartifactId>
<version>6.0.0version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.25version>
<scope>runtimescope>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.44version>
dependency>
application.yml
文件server:
port: 8888
spring:
datasource:
url: jdbc:mysql://localhost:3306/activiti_test?useSSL=true
driver-class-name: com.mysql.jdbc.Driver
username: root
password: welcome123
activiti:
database-schema-update: true
database-schema: activiti_test
history-level: full
db-history-used: true # 检查历史表是否存在
db-identity-used: false # 检查身份信息表是否存在
check-process-definitions: false # 自动部署验证设置:true-开启(默认)、false-关闭
database-schema-update 分为 4 种
flase: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。(生产环境常用)
true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。(开发时常用)
create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。(单元测试常用)
drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)。
activiti的历史记录级别分为以下四种:none, activity, audit, full,级别分别由低到高能够显示不同的日志级别信息:
none: 不记录历史流程,性能高,流程结束后不可读取
activity: 归档流程实例和活动实例,流程变量不同步
audit: 默认值,在activiti基础上同步变量值,保存表单属性
full: 性能较差,记录所有实例和变量细节变化,最完整的历史记录,如果需要日后跟踪详细可以开启full(一般不建议开启)
MyProcess.bpmn20.xml
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
<process id="myProcess" name="My process" isExecutable="true">
<startEvent id="startevent1" name="Start">startEvent>
<userTask id="s1" name="提交请假申请">userTask>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="s1">sequenceFlow>
<userTask id="s2" name="领导审批" activiti:assignee="boss">userTask>
<sequenceFlow id="flow2" sourceRef="s1" targetRef="s2">sequenceFlow>
<userTask id="s3" name="总经理审批" activiti:candidateUsers="${houxuanren}">userTask>
<sequenceFlow id="flow3" sourceRef="s2" targetRef="s3">sequenceFlow>
<endEvent id="endevent1" name="End">endEvent>
<sequenceFlow id="flow4" sourceRef="s3" targetRef="endevent1">sequenceFlow>
process>
<bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
<bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="100.0" y="250.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="s1" id="BPMNShape_s1">
<omgdc:Bounds height="55.0" width="105.0" x="180.0" y="240.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="s2" id="BPMNShape_s2">
<omgdc:Bounds height="55.0" width="105.0" x="330.0" y="240.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="s3" id="BPMNShape_s3">
<omgdc:Bounds height="55.0" width="105.0" x="480.0" y="240.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="630.0" y="250.0">omgdc:Bounds>
bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="135.0" y="267.0">omgdi:waypoint>
<omgdi:waypoint x="180.0" y="267.0">omgdi:waypoint>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="285.0" y="267.0">omgdi:waypoint>
<omgdi:waypoint x="330.0" y="267.0">omgdi:waypoint>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
<omgdi:waypoint x="435.0" y="267.0">omgdi:waypoint>
<omgdi:waypoint x="480.0" y="267.0">omgdi:waypoint>
bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
<omgdi:waypoint x="585.0" y="267.0">omgdi:waypoint>
<omgdi:waypoint x="630.0" y="267.0">omgdi:waypoint>
bpmndi:BPMNEdge>
bpmndi:BPMNPlane>
bpmndi:BPMNDiagram>
definitions>
@Test
public void init() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.close();
}
@Test
public void testDeploy() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
Deployment deployment = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
.createDeployment()//创建一个部署对象
.name("请假流程")//添加部署名称
.category("测试流程类别")
.addClasspathResource("flow/MyProcess.bpmn20.xml")//从classpath的资源中加载,一次只能加载一个文件
.deploy();//完成部署
System.out.println("部署ID:" + deployment.getId());
System.out.println("部署名称:" + deployment.getName());
}
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<ProcessDefinition> list = processEngine.getRepositoryService()//与流程定义和部署对象相关的Service
.createProcessDefinitionQuery()//创建一个流程定义查询
/*指定查询条件,where条件*/
//.deploymentId(deploymentId)//使用部署对象ID查询
//.processDefinitionId(processDefinitionId)//使用流程定义ID查询
//.processDefinitionKey(processDefinitionKey)//使用流程定义的KEY查询
//.processDefinitionNameLike(processDefinitionNameLike)//使用流程定义的名称模糊查询
/*排序*/
.orderByProcessDefinitionVersion().asc()//按照版本的升序排列
//.orderByProcessDefinitionName().desc()//按照流程定义的名称降序排列
.list();//返回一个集合列表,封装流程定义
//.singleResult();//返回唯一结果集
//.count();//返回结果集数量
//.listPage(firstResult, maxResults)//分页查询
if (list != null && list.size() > 0) {
for (ProcessDefinition processDefinition : list) {
System.out.println("流程定义ID:" + processDefinition.getId());//流程定义的key+版本+随机生成数
System.out.println("流程定义名称:" + processDefinition.getName());//对应HelloWorld.bpmn文件中的name属性值
System.out.println("流程定义的key:" + processDefinition.getKey());//对应HelloWorld.bpmn文件中的id属性值
System.out.println("流程定义的版本:" + processDefinition.getVersion());//当流程定义的key值相同的情况下,版本升级,默认从1开始
System.out.println("资源名称bpmn文件:" + processDefinition.getResourceName());
System.out.println("资源名称png文件:" + processDefinition.getDiagramResourceName());
System.out.println("部署对象ID:" + processDefinition.getDeploymentId());
}
}
@Test
public void startProcess() {
String processDefineId = "myProcess"; // xml定义的流程id
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
ProcessInstance instance = processEngine.getRuntimeService().startProcessInstanceByKey(processDefineId);
//未流程定义设置名称
processEngine.getRuntimeService().setProcessInstanceName(instance.getId(),"请假流程");
}
@Test
public void queryInstance() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<HistoricProcessInstance> list = processEngine.getHistoryService().createHistoricProcessInstanceQuery().list();
for (HistoricProcessInstance processInstance : list) {
System.out.println(processInstance.getName());
}
}
@Test
public void queryTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
TaskQuery taskQuery = taskService.createTaskQuery();
// taskQuery.taskAssignee("张三");
List<Task> list = taskQuery.list();
for (Task task : list) {
System.out.println(task.getName());
System.out.println(task.getId());
System.out.println(task.getAssignee());
System.out.println(task.getClaimTime());
System.out.println(task.getProcessDefinitionId());
System.out.println(task.getProcessInstanceId());
Map<String, VariableInstance> variableInstances = taskService.getVariableInstances(task.getId());
System.out.println(variableInstances);
Map<String, Object> variablesLocal = taskService.getVariablesLocal(task.getId());
System.out.println(variablesLocal);
}
}
@Test
public void queryHistoryTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
List<HistoricTaskInstance> list = processEngine.getHistoryService().createHistoricTaskInstanceQuery().orderByTaskCreateTime().desc()
.list();
if (!CollectionUtils.isEmpty(list)) {
Map<String, List<HistoricTaskInstance>> map = list.stream().collect(Collectors.groupingBy(HistoricTaskInstance::getExecutionId));
for (Map.Entry<String, List<HistoricTaskInstance>> entry : map.entrySet()) {
List<HistoricTaskInstance> value = entry.getValue();
System.out.print("流程实例:(" + value.get(0).getProcessInstanceId() + ")");
for (HistoricTaskInstance instance : value) {
System.out.print(instance.getName() + "(" + instance.getAssignee() + ") ---->");
}
if (value.get(value.size() - 1).getEndTime() != null) {
System.out.print("end");
} else {
System.out.print("processing");
}
System.out.println("------------------------------------------");
}
}
}
String taskId = "15005";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
task.setAssignee("tom");
Map<String, Object> map1 = new HashMap<>();
map1.put("apply", "小米");
map1.put("age", 12);
taskService.setVariables(taskId, map1);
Map<String, Object> map2 = new HashMap<>();
map2.put("aaaaaaaaaa", 1234);
taskService.setVariablesLocal(taskId, map2);
@Test
public void claim() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().orderByTaskCreateTime().desc().list().get(0);
if (task.getAssignee() != null) {
System.out.println("已签收");
} else {
taskService.claim(task.getId(), "张三");
}
}
@Test
public void unClaim() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().orderByTaskCreateTime().desc().list().get(0);
if (task.getAssignee() == null) {
System.out.println("未指派");
} else {
taskService.unclaim(task.getId());
}
}
@Test
public void complete() {
String taskId = "57505";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Map<String, Object> map1 = new HashMap<>();
map1.put("test", "22222");
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
taskService.complete(task.getId(), map1);
List<Task> tasks = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
if (!CollectionUtils.isEmpty(tasks)) {
for (Task task1 : tasks) {
taskService.setVariable(task1.getId(),"status",false);
taskService.setVariableLocal(task1.getId(), "taskStatus", "processing");
}
}
}
单元例子涉及流程变量和任务变量的设置,详细学习需自己手动敲例子去感受Activiti里面更多的API
Activiti使用到的表都是ACT_
前缀,列名都是有下划线
后缀,防止关键字冲突。
ACT_RE_*
:’RE’表示repository(存储 ),RepositoryService接口所操作的表。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。
ACT_RU_*
:‘RU’表示runtime,运行时表-RuntimeService。这是运行时的表存储着流程变量,用户任务,变量,职责(job)等运行时的数据。Activiti只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。
ACT_ID_*
:’ID’表示identity (组织机构),IdentityService接口所操作的表。用户记录,流程中使用到的用户和组。这些表包含标识的信息,如用户,用户组,等等。
ACT_HI_*
:’HI’表示history,历史数据表,HistoryService。就是这些表包含着流程执行的历史相关数据,如结束的流程实例,变量,任务,等等
ACT_GE_*
:全局通用数据及设置(general),各种情况都使用的数据。
表名 | 描述 |
---|---|
ACT_EVT_LOG | 事件日志表 |
ACT_GE_BYTEARRAY | 二进制数据表 |
ACT_GE_PROPERTY | 属性数据表,存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录。 |
ACT_HI_ACTINST | 历史节点表 |
ACT_HI_ATTACHMENT | 历史附件表 |
ACT_HI_COMMENT | 历史意见表 |
ACT_HI_DETAIL | 历史详情表,提供历史变量的查询 |
ACT_HI_IDENTITYLINK | 历史流程人员表 |
ACT_HI_PROCINST | 历史流程实例表 |
ACT_HI_TASKINST | 历史流程任务表 |
ACT_HI_VARINST | 历史变量表 |
ACT_ID_GROUP | 用户组信息表 |
ACT_ID_INFO | 用户扩展信息表 |
ACT_ID_MEMBERSHIP | 用户与用户组关系信息表 |
ACT_ID_USER | 用户信息表 |
ACT_PROCDEF_INFO | |
ACT_RE_DEPLOYMENT | 部署信息表 |
ACT_RE_MODEL | 流程设计模型部署表 |
ACT_RE_PROCDEF | 流程定义数据表 |
ACT_RU_EVENT_SUBSCR | throwEvent、catchEvent时间监听信息表 |
ACT_RU_EXECUTION | 运行时流程执行实例表 |
ACT_RU_IDENTITYLINK | 运行时流程人员表,主要存储任务节点与参与者相关信息 |
ACT_RU_JOB | 运行时定时任务数据表 |
ACT_RU_TASK | 运行时任务节点表 |
ACT_RU_VARIABLE | 运行时流程变量数据表 |