本文已收录在Github,关注我,紧跟本系列专栏文章,咱们下篇再续!
Java项目集成 Activiti7 完成一个简单工作流。
添加Activiti7依赖:
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M4</version>
</dependency>
<dependency>
<groupId>org.activiti.dependencies</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>7.1.0.M4</version>
<type>pom</type>
</dependency>
将工作流的定义文件(如BPMN文件、流程图等)发布到Activiti引擎中的过程,使流程定义能够被系统识别和使用。
@PostMapping(value = "/addDeploymentByString")
public AjaxResponse addDeploymentByString(@RequestParam("stringBPMN") String stringBPMN) {
try {
Deployment deployment = repositoryService.createDeployment()
.addString("CreateWithBPMNJS.bpmn", stringBPMN)
.name("不知道在哪显示的部署名称")
.deploy();
return AjaxResponse.AjaxData(GlobalConfig.ResponseCode.SUCCESS.getCode(),
GlobalConfig.ResponseCode.SUCCESS.getDesc(), deployment.getId());
} catch (Exception e) {
// 异常处理
}
}
从代码中可以看到项目支持多种部署方式:
部署一个zip:
//通过ZIP部署流程
@Test
public void initDeploymentZIP() {
InputStream fileInputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("BPMN/Part1_DeploymentV2.zip");
ZipInputStream zip = new ZipInputStream(fileInputStream);
Deployment deployment = repoService.createDeployment()
.addZipInputStream(zip)
.name("流程部署测试zip")
.deploy();
System.out.println(deployment.getName());
}
最终生成的是什么呢?没错,zip 里的 两个文件,同属于一个部署:
每次部署会创建新的流程定义版本,项目中还通过SQL扩展了部署表:
alter table ACT_RE_DEPLOYMENT add column PROJECT_RELEASE_VERSION_ varchar(255) DEFAULT NULL;
alter table ACT_RE_DEPLOYMENT add column VERSION_ varchar(255) DEFAULT NULL;
部署后会生成ProcessDefinition(流程定义),项目通过以下代码查询流程定义:
@GetMapping(value = "/getDefinitions")
public AjaxResponse getDefinitions() {
try {
List<HashMap<String, Object>> listMap = new ArrayList<>();
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
// 按版本排序
list.sort((y,x)->x.getVersion()-y.getVersion());
// 遍历处理流程定义
// ...
} catch (Exception e) {
// 异常处理
}
}
项目实现了部署的查询和删除功能:
@GetMapping(value = "/getDeployments")
public AjaxResponse getDeployments() {
// 查询所有部署
}
@GetMapping(value = "/delDefinition")
public AjaxResponse delDefinition(@RequestParam("depID") String depID, @RequestParam("pdID") String pdID) {
// 删除部署及相关数据
}
在这个Activiti工作流项目中,Deployment是连接流程设计和流程执行的桥梁,是整个工作流系统的基础。通过部署操作,将流程定义文件转化为系统可识别和执行的流程定义对象,为后续的流程实例创建和任务执行提供必要条件。
先修改配置文件 application.yml 连接本地 MySQL,手动创建 activity 数据库。并确保已经运行过一次项目,让Activiti自动初始化必要的表结构:
// 通过bpmn部署流程
@Test
public void initDeploymentBPMN() {
String filename = "BPMN/Part4_Task_claim.bpmn";
Deployment deployment = repoService.createDeployment()
.addClasspathResource(filename)
.name("流程部署测试候选人task")
.deploy();
System.out.println(deployment.getName());
}
第一次启动项目,执行以上用例时,代码报错:
org.apache.ibatis.exceptions.PersistenceException:
### Error updating database. Cause: java.sql.SQLSyntaxErrorException: Unknown column 'VERSION_' in 'field list'
### The error may exist in org/activiti/db/mapping/entity/Deployment.xml
### The error may involve org.activiti.engine.impl.persistence.entity.DeploymentEntityImpl.insertDeployment-Inline
### The error occurred while setting parameters
### SQL: insert into ACT_RE_DEPLOYMENT(ID_, NAME_, CATEGORY_, KEY_, TENANT_ID_, DEPLOY_TIME_, ENGINE_VERSION_, VERSION_, PROJECT_RELEASE_VERSION_) values(?, ?, ?, ?, ?, ?, ?, ?, ?)
### Cause: java.sql.SQLSyntaxErrorException: Unknown column 'VERSION_' in 'field list'
典型的Activiti 7 M4版本的已知Bug - 表结构定义中缺少字段导致的问题。根据错误信息,当尝试向ACTRE_DEPLOYMENT表插入数据时,系统找不到VERSION字段。执行项目根目录下的user.sql文件中的SQL语句即可。向ACT_RE_DEPLOYMENT表中添加Activiti 7 M4版本缺失的两个字段。重新执行该用例方法,运行成功!
属于Repository服务相关的表(RE前缀代表Repository)。
看表里创的数据:
存储流程定义的二进制文件资源。
Part1_Deployment.java
测试类中,可以看到你通过.addClasspathResource()
和.addZipInputStream()
添加的资源都会被存储到这个ACT_RE_DEPLOYMENT
表关联:每次部署创建的资源都会有一个对应的部署IDACT_RE_PROCDEF
表关联:流程定义引用这些资源执行以下代码时:
Deployment deployment = repoService.createDeployment()
.addClasspathResource(filename)
.name("流程部署测试V1")
.deploy();
底层会将该BPMN文件的内容读取并存储到ACT_GE_BYTEARRAY表,同时创建相应的部署记录和流程定义记录。
这种设计使得Activiti运行时直接从数据库获取流程定义,而无需每次从文件系统读取,提高执行效率和可靠性。
同时生成一个图片即可。但其实.bpmn文件就能用bpmn.js插件渲染出来了。
// 通过bpmn部署流程
@Test
public void initDeploymentBPMN() {
String filename = "BPMN/Part4_Task_claim.bpmn";
String pngname="BPMN/Part1_Deployment.png";
Deployment deployment = repoService.createDeployment()
.addClasspathResource(filename)
.addClasspathResource(pngname)//图片
.name("流程部署测试V1")
.deploy();
System.out.println(deployment.getName());
}
说明同属于一个部署:
和 deploymentid 一对一:
$ ID_ = key + 部署次数版本 + id$
既不是因为表的字段太多,也不是因为一对多,就是设计成了一对一关系。
@Test
public void getDefinitions() {
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
.list();
for (ProcessDefinition pd : list) {
System.out.println("------流程定义--------");
System.out.println("Name:" + pd.getName());
System.out.println("Key:" + pd.getKey());
System.out.println("ResourceName:" + pd.getResourceName());
System.out.println("DeploymentId:" + pd.getDeploymentId());
System.out.println("Version:" + pd.getVersion());
}
}
@Test
public void delDefinition() {
String pdID = "44b15cfe-ce3e-11ea-92a3-dcfb4875e032";
repositoryService.deleteDeployment(pdID, true);
System.out.println("删除流程定义成功");
}
ProcessDefinition与ProcessInstance是一对多关系,理解为:行动计划与具体行动的关系。
ProcessDefinition 是对业务流程的静态描述,定义了流程的结构、节点、连线和规则,相当于流程的"蓝图"。每个流程定义在部署后会有唯一标识,并支持版本控制。
getDefinitions()
方法查询所有流程定义,获取名称、键值、资源名等基本信息ProcessInstanceController
中获取流程定义信息并返回给前端展示Part1_Deployment.java
中通过 BPMN 文件部署流程,生成流程定义delDefinition()
方法中删除特定流程定义ProcessInstanceController
中通过流程定义键(processDefinitionKey)启动流程实例ProcessDefinitionController
中可以看到流程定义支持版本控制list.sort((y,x)->x.getVersion()-y.getVersion())
实现按版本排序getResourceName()
可获取// 查询流程定义
@Test
public void getDefinitions() {
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
.list();
for (ProcessDefinition pd : list) {
System.out.println("------流程定义--------");
System.out.println("Name:" + pd.getName());
System.out.println("Key:" + pd.getKey());
System.out.println("ResourceName:" + pd.getResourceName());
System.out.println("DeploymentId:" + pd.getDeploymentId());
System.out.println("Version:" + pd.getVersion());
}
}
综上所述,ProcessDefinition是连接流程设计、流程部署和流程执行的核心概念,为工作流的生命周期管理提供基础支持。
需要的就是一个流程的 key:
@Test
public void initProcessInstance(){
// 1、获取页面表单填报的内容,请假时间,请假事由,String fromData
// 2、fromData 写入业务表,返回业务表主键ID==businessKey
// 3、把业务数据与Activiti7流程数据关联
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess_claim","bKey002");
System.out.println("流程实例ID:"+processInstance.getProcessDefinitionId());
}
@Test
public void getProcessInstances(){
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().list();
for(ProcessInstance pi : list){
System.out.println("--------流程实例------");
System.out.println("ProcessInstanceId:"+pi.getProcessInstanceId());
System.out.println("ProcessDefinitionId:"+pi.getProcessDefinitionId());
System.out.println("isEnded"+pi.isEnded());
System.out.println("isSuspended:"+pi.isSuspended());
}
}
@Test
public void activitieProcessInstance(){
// runtimeService.suspendProcessInstanceById("73f0fb9a-ce5b-11ea-bf67-dcfb4875e032");
//System.out.println("挂起流程实例");
runtimeService.activateProcessInstanceById("73f0fb9a-ce5b-11ea-bf67-dcfb4875e032");
System.out.println("激活流程实例");
}
@Test
public void delProcessInstance(){
runtimeService.deleteProcessInstance("73f0fb9a-ce5b-11ea-bf67-dcfb4875e032","删着玩");
System.out.println("删除流程实例");
}
代表流程执行过程中需要人工处理的环节。
Task接口用于表示需要人类用户执行的任务,Task接口定义:
public interface Task extends TaskInfo {
// 任务相关属性和操作
}
通过TaskService
和TaskRuntime
提供多种任务操作:
Task具有多种状态,如代码中显示:
assignee
有具体用户)complete
方法标记)suspend
方法实现)通过assignee
和候选人组实现任务访问控制:
List<Task> list = taskService.createTaskQuery()
.taskAssignee("bajie")
.list();
项目中TaskController
负责向前端提供任务相关API,如获取当前用户的代办任务:
@GetMapping(value = "/getTasks")
public AjaxResponse getTasks() {
// 获取并返回任务列表
}
Task是Activiti工作流引擎中连接业务流程和实际操作人员的桥梁,通过它可以实现人工审批、处理等业务场景的工作流管理。
任务的图形化是以矩形为基础,在左侧添加具体的图标,用来描述一种特定任务类型。
用户任务需要人来参与,需要人为触发。
关注用户任务:
下面串起这些概念:
猪头三发起了报销请求:
JavaEdge 审核报销请求:
注意流程 id 名为:myProcess_Task,
先bpmn部署该流程:
public void startDeploymentBPMN() {
String filename = "BPMN/Part4_Task.bpmn";
Deployment deployment = repoService.createDeployment()
.addClasspathResource(filename)
.name("Part4_Task")
.deploy();
}
再启动一个这样的流程实例:
public void initProcessInstance(){
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess_Task","bKey002");
}
最后,我们来查询任务执行情况:
@Test
public void getTasks(){
List<Task> list = taskService.createTaskQuery().list();
for(Task tk : list){
System.out.println("Id:"+tk.getId());
System.out.println("Name:"+tk.getName());
System.out.println("Assignee:"+tk.getAssignee());
}
}
output:
Id:9ec8d75e-9b86-11ef-8c93-a202cf5d45d9
Name:发起报销
Assignee:猪头三
该全量任务列表方法一般是由管理员查看任务执行情况。
@Test
public void getTasksByAssignee(){
List<Task> list = taskService.createTaskQuery()
.taskAssignee("猪头三")
.list();
for(Task tk : list){
System.out.println("Id:"+tk.getId());
System.out.println("Name:"+tk.getName());
System.out.println("Assignee:"+tk.getAssignee());
}
}
output:
Id:9ec8d75e-9b86-11ef-8c93-a202cf5d45d9
Name:发起报销
Assignee:猪头三
创建一个 ProcessEngineConfiguration
实例来初始化流程引擎:
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
public class ActivitiConfig {
public static ProcessEngine buildProcessEngine() {
ProcessEngineConfiguration config = ProcessEngineConfiguration
.createStandaloneInMemProcessEngineConfiguration();
config.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
config.setJdbcUrl("jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000");
config.setJdbcDriver("org.h2.Driver");
config.setJdbcUsername("sa");
config.setJdbcPassword("");
return config.buildProcessEngine();
}
}
上面的代码创建了一个内存数据库中的流程引擎配置,这在开发和测试阶段非常便捷。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。