
package org.bingo.activiti;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.junit.Test;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
public class Test01 {
/**
* 生成activiti相关表结构
*/
@Test
public void test01(){
//使用classpath下的activiti.cfg.xml中的配置来创建ProcessEngine对象
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
System.out.println(engine);
}
/**
* 实现单个文件部署
*/
@Test
public void test03(){
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService service = engine.getRepositoryService();
Deployment deploy = service.createDeployment()
.addClasspathResource("bpmn/execution.bpmn")
.addClasspathResource("bpmn/execution.png")
.name("请假流程部署")
.key("execution-key")
.deploy();
System.out.println("流程部署id: "+deploy.getId());
System.out.println("流程部署name: "+deploy.getName());
System.out.println("流程部署key: "+deploy.getKey());
}
/**
* 启动流程实例
*/
@Test
public void test05(){
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RuntimeService service = engine.getRuntimeService();
String id = "execution:1:4";
ProcessInstance processInstance = service.startProcessInstanceById(id);
System.out.println("流程实例的businessKey: "+processInstance.getBusinessKey());
System.out.println("流程实例的Name: "+processInstance.getName());
System.out.println("流程实例的流程部署id: "+processInstance.getDeploymentId());
System.out.println("流程实例的流程部署key: "+processInstance.getProcessDefinitionKey());
System.out.println("流程实例的startUserId: "+processInstance.getStartUserId());
}
/**
* 任务查询
*/
@Test
public void test06(){
String assignee = "lisi";
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = engine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("execution")
.taskAssignee(assignee)
.list();
for (Task task : list) {
System.out.println("流程实例id: " + task.getProcessInstanceId());
System.out.println("任务id: " + task.getId());
System.out.println("任务负责人: " + task.getAssignee());
System.out.println("任务名称呢个: " + task.getName());
}
}
/**
* 流程任务处理
*/
@Test
public void test07(){
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = engine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("execution")
.taskAssignee("lisi")
.singleResult();
taskService.complete(task.getId());
}
public static void main(String[] args) throws Exception{
backProcess("32502", "N0001");
}
/**
* 退回到指定节点
* @param taskId 当前任务ID
* @param preNode 上一个节点key
*/
public static void backProcess(String taskId, String preNode) throws Exception {
if(StringUtils.isEmpty(taskId)){
throw new RuntimeException("任务taskId为空");
}
if(StringUtils.isEmpty(preNode)){
throw new RuntimeException("退回节点preNode为空");
}
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = engine.getHistoryService();
RuntimeService runtimeService = engine.getRuntimeService();
TaskService taskService = engine.getTaskService();
RepositoryService repositoryService = engine.getRepositoryService();
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
String processInstanceId = task.getProcessInstanceId();
// 取得所有历史任务按时间降序排序
List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.orderByTaskCreateTime()
.desc()
.list();
if (CollectionUtils.isEmpty(htiList) || htiList.size() < 2) {
return;
}
// list里面节点等于退回到的指定节点
HistoricTaskInstance lastTask = null;
for (HistoricTaskInstance instance : htiList) {
String key = instance.getTaskDefinitionKey();
if(preNode.equals(key)){
lastTask = instance;
}
}
if(lastTask == null){
throw new RuntimeException("没有找到指定的退回节点");
}
// 当前节点的executionId
String curExecutionId = task.getExecutionId();
// 上个节点的taskId
String lastTaskId = lastTask.getId();
// 上个节点的executionId
String lastExecutionId = lastTask.getExecutionId();
if (null == lastTaskId) {
throw new Exception("LAST TASK IS NULL");
}
String processDefinitionId = lastTask.getProcessDefinitionId();
//通过processDefinitionId从act_re_procdef查出一条记录, 通过act_re_procdef.DEPLOYMENT_ID_关联到act_ge_bytearray表查出存在数据库的bpmn文件信息
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
String lastActivityId = null;
List<HistoricActivityInstance> haiFinishedList = historyService.createHistoricActivityInstanceQuery()
.executionId(lastExecutionId).finished().list();
for (HistoricActivityInstance hai : haiFinishedList) {
if (lastTaskId.equals(hai.getTaskId())) {
// 得到ActivityId,只有HistoricActivityInstance对象里才有此方法
lastActivityId = hai.getActivityId();
break;
}
}
// 得到上个节点的信息
FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivityId);
// 取得当前节点的信息
Execution execution = runtimeService.createExecutionQuery().executionId(curExecutionId).singleResult();
String curActivityId = execution.getActivityId();
FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(curActivityId);
//记录当前节点的原活动方向
List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
oriSequenceFlows.addAll(curFlowNode.getOutgoingFlows());
//清理活动方向
curFlowNode.getOutgoingFlows().clear();
//建立新方向
List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("newSequenceFlowId");
newSequenceFlow.setSourceFlowElement(curFlowNode);
newSequenceFlow.setTargetFlowElement(lastFlowNode);
newSequenceFlowList.add(newSequenceFlow);
curFlowNode.setOutgoingFlows(newSequenceFlowList);
// 完成任务
taskService.complete(task.getId());
//恢复原方向
curFlowNode.setOutgoingFlows(oriSequenceFlows);
Task nextTask = taskService
.createTaskQuery().processInstanceId(processInstanceId).singleResult();
// 设置执行人
if(nextTask!=null) {
taskService.setAssignee(nextTask.getId(), lastTask.getAssignee());
}
}
}
下面是execution.xml文件, 生成png图片后改后缀为.bpmn, 2个文件放到maven项目的resources/bpmn目录下
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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="m1639913348109" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
<process id="execution" isClosed="false" isExecutable="true" name="外出请假流程" processType="None">
<startEvent id="N0000" name="StartEvent"/>
<userTask activiti:assignee="zhangsan" activiti:exclusive="true" id="N0001" name="创建请假单"/>
<userTask activiti:assignee="lisi" activiti:exclusive="true" id="N0002" name="经理审批"/>
<userTask activiti:assignee="wangwu" activiti:exclusive="true" id="N0003" name="总经理审批"/>
<userTask activiti:assignee="zhaoliu" activiti:exclusive="true" id="N0004" name="财务审批"/>
<endEvent id="N0005" name="EndEvent"/>
<sequenceFlow id="_9" sourceRef="N0000" targetRef="N0001"/>
<sequenceFlow id="_10" sourceRef="N0001" targetRef="N0002"/>
<sequenceFlow id="_11" sourceRef="N0002" targetRef="N0003"/>
<sequenceFlow id="_12" sourceRef="N0003" targetRef="N0004"/>
<sequenceFlow id="_13" sourceRef="N0004" targetRef="N0005"/>
</process>
<bpmndi:BPMNDiagram documentation="background=#3C3F41;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="execution">
<bpmndi:BPMNShape bpmnElement="N0000" id="Shape-N0000">
<omgdc:Bounds height="32.0" width="32.0" x="170.0" y="10.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="N0001" id="Shape-N0001">
<omgdc:Bounds height="55.0" width="85.0" x="145.0" y="90.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="N0002" id="Shape-N0002">
<omgdc:Bounds height="55.0" width="85.0" x="145.0" y="200.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="N0003" id="Shape-N0003">
<omgdc:Bounds height="55.0" width="85.0" x="145.0" y="300.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="N0004" id="Shape-N0004">
<omgdc:Bounds height="55.0" width="85.0" x="145.0" y="395.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="N0005" id="Shape-N0005">
<omgdc:Bounds height="32.0" width="32.0" x="170.0" y="490.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="N0004" targetElement="N0005">
<omgdi:waypoint x="186.0" y="450.0"/>
<omgdi:waypoint x="186.0" y="490.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="N0003" targetElement="N0004">
<omgdi:waypoint x="187.5" y="355.0"/>
<omgdi:waypoint x="187.5" y="395.0"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="N0000" targetElement="N0001">
<omgdi:waypoint x="186.0" y="42.0"/>
<omgdi:waypoint x="186.0" y="90.0"/>
<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="N0002" targetElement="N0003">
<omgdi:waypoint x="187.5" y="255.0"/>
<omgdi:waypoint x="187.5" 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="_10" id="BPMNEdge__10" sourceElement="N0001" targetElement="N0002">
<omgdi:waypoint x="187.5" y="145.0"/>
<omgdi:waypoint x="187.5" y="200.0"/>
<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>
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!-- 连接数据的配置 -->
<!--<property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf8"></property>
<property name="jdbcUsername" value="root"></property>
<property name="jdbcPassword" value="root"></property>-->
<!-- 没有表创建表 -->
<property name="databaseSchemaUpdate" value="true"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf8"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="maxActive" value="3"></property>
<property name="maxIdle" value="2"></property>
</bean>
</beans>
log4j.properties
### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://log/act/activiti.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.bingo</groupId>
<artifactId>activiti</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<slf4j-version>1.6.6</slf4j-version>
<log4j-version>1.2.12</log4j-version>
<activiti-version>7.0.0.Beta1</activiti-version>
<mysql-version>8.0.25</mysql-version>
<mybatis-version>3.4.5</mybatis-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>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>${activiti-version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>${activiti-version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>${activiti-version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>${activiti-version}</version>
<exclusions>
<exclusion>
<groupId>com.github.jgraph</groupId>
<artifactId>jgraph</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>${activiti-version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis-version}</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>
<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>
</project>
版权声明:本文为weixin_42490383原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。