维维
V1
2023/03/23阅读:33主题:默认主题
从一个简单的小流程开始
从一个简单的小流程开始
整合好基础框架以后,就可以开始实现简单的流程
生成BPMN xml文件(制作流程图)
-
idea插件
-
idea安装插件
-

-
resource文件夹下创建processes文件夹,鼠标邮件点击下图选中选项,设置文件名,生成一个 bpmn20.xml
后缀的文件

3. 生成文件内容
<?xml version="1.0" encoding="UTF-8"?>
<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/processdef">
<process id="test" name="test" isExecutable="true">
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_test">
<bpmndi:BPMNPlane bpmnElement="test" id="BPMNPlane_test">
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
-
打开文件,鼠标右键点击

-
弹出工具窗口,然后邮件点击空白开始制作流程图

-
绘制出差流程图。
activiti完成出差流程
使用出差申请流程来举例:
出差需要发起人提交出差申请单,然后发起人的上级进行审批。根据业务设计流程图如下(画图方式可以选择idea插件或者activiti官方提供的画图工具):

提交出差申请在bpmn中是一个用户任务,此节点需要设置任务处理人

然后xml文件会对应产生变化,节点ID,连线ID都不能为空,且不能数字开头
<?xml version="1.0" encoding="UTF-8"?>
<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/processdef">
<process id="出差-chuchai" name="出差-chuchai" isExecutable="true">
<startEvent id="sid-bdd9ce98-1759-4069-ab01-31fd04ff71d2" name="开始"/>
<userTask id="sid-cfe6c629-47ed-46e2-9f73-cededa30489e" activiti:assignee="${startUser}" name="提交出差申请" isForCompensation="false" activiti:async="false"/>
<endEvent id="sid-885e7495-3705-4bb7-ab1b-a409158acf2d" name="结束"/>
<userTask id="sid-c69f1bed-624e-47ba-8e2f-a5e747695d47" activiti:assignee="${approvalUser}" name="上级审批"/>
<sequenceFlow id="sid-34139cbc-430b-4b01-9c39-93692289b4c5" sourceRef="sid-bdd9ce98-1759-4069-ab01-31fd04ff71d2" targetRef="sid-cfe6c629-47ed-46e2-9f73-cededa30489e"/>
<sequenceFlow id="sid-750efcec-5f98-4cd7-a8b4-82d6cc993f35" sourceRef="sid-cfe6c629-47ed-46e2-9f73-cededa30489e" targetRef="sid-c69f1bed-624e-47ba-8e2f-a5e747695d47">
</sequenceFlow>
<sequenceFlow id="sid-d16b767e-e90e-4102-8bb3-009f87cc7c83" sourceRef="sid-c69f1bed-624e-47ba-8e2f-a5e747695d47" targetRef="sid-885e7495-3705-4bb7-ab1b-a409158acf2d"/>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_出差-chuchai">
<bpmndi:BPMNPlane bpmnElement="出差-chuchai" id="BPMNPlane_出差-chuchai">
<bpmndi:BPMNShape id="shape-9ad65875-b57e-44ee-8995-9bd2c624ea70" bpmnElement="sid-bdd9ce98-1759-4069-ab01-31fd04ff71d2">
<omgdc:Bounds x="-15.0" y="0.0" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-042ca34a-dcd9-412a-826b-8b2f707eda3e" bpmnElement="sid-cfe6c629-47ed-46e2-9f73-cededa30489e">
<omgdc:Bounds x="70.0" y="-25.0" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-4d141cd8-4d18-4c9c-8199-da900581dca6" bpmnElement="sid-885e7495-3705-4bb7-ab1b-a409158acf2d">
<omgdc:Bounds x="430.0" y="9.536743E-7" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="sid-ad4f648a-b980-4700-b29b-c7ad3b87fbb1" bpmnElement="sid-c69f1bed-624e-47ba-8e2f-a5e747695d47">
<omgdc:Bounds x="255.50002" y="-25.0" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-2957cc4d-1d9e-49c5-9687-8af6c4456003" bpmnElement="sid-34139cbc-430b-4b01-9c39-93692289b4c5">
<omgdi:waypoint x="15.0" y="15.0"/>
<omgdi:waypoint x="70.0" y="15.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-24aedcd8-09e1-4ce6-b5ae-089fd99b3a05" bpmnElement="sid-750efcec-5f98-4cd7-a8b4-82d6cc993f35">
<omgdi:waypoint x="170.0" y="15.0"/>
<omgdi:waypoint x="255.50002" y="15.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-8adf1d84-1d96-4e4c-afa6-e618344cbe01" bpmnElement="sid-d16b767e-e90e-4102-8bb3-009f87cc7c83">
<omgdi:waypoint x="355.5" y="15.0"/>
<omgdi:waypoint x="430.0" y="15.000001"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
流程定义部署
然后要把这个你定义的流程图放到activiti的数据库中(流程定义部署)
调用 activiti 的 repositoryService
接口 添加部署:
public DeployDTO createApproval(CreateApprovalVO approvalVO) {
Model model = repositoryService.createModelQuery().modelKey(approvalVO.getKey()).singleResult();
if(!Objects.isNull(model)){
throw new BaseException(ApprovalErrorEnum.APPROVAL_860002);
}
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
// 定义流程资源名称
.name(approvalVO.getName())
.key(approvalVO.getKey())
// 加载待部署的资源,可以多次引用
.addClasspathResource("processes/出差-chuchai.bpmn.xml")
// 完成部署
.deploy();
return setValue(deploy);
}
返回数据:
{
"code": 200,
"message": "成功",
"data": {
"id": "300001",
"key": "chuchai",
"name": "出差",
"category": null,
"deploymentTime": "2023-03-23T08:05:06.664+00:00",
"tenantId": ""
},
"success": true
}
这就是部署完成了。部署以后就可以启动流程了(类似java中封装类与new对象的关系)
执行此操作后activiti会将上边代码中指定的bpm文件和图片文件保存在activiti数据库。
流程定义部署后操作activiti的3张表如下:
act_re_deployment 流程定义部署表,每部署一次增加一条记录
act_re_procdef 流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
act_ge_bytearray 流程资源表
启动流程
// 请求参数:
// {
// "key": "出差-chuchai",
// "businessKey": "1234567890",
// "variablesMap":{
// "startUser":"小红",
// "approvalUser":"小明"
// }
// }
//startUser 和 approvalUser 是咱们在 定义流程的时候设置的流程变量,所以在发起流程的时候要把参数传进去,否则报错
//(后面会说到其他设置审批人的方式)
@Override
@Transactional(rollbackFor = Exception.class)
public DeploymentDTO startApproval(StartApprovalVO vo) {
//第一个参数是流程定义key (出差-chuchai),第二个是你自己的业务id,第三个是流程变量
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey(vo.getKey(),vo.getBusinessKey(),vo.getVariablesMap());
List<Task> list = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
for (Task task : list) {
SendMailCmd sendMailCmd = new SendMailCmd(task.getId(),processInstance.getId());
managementService.executeCommand(sendMailCmd);
}
DeploymentDTO dto = new DeploymentDTO();
dto.setBusinessKey(processInstance.getBusinessKey());
dto.setIsSuspended(processInstance.isSuspended());
dto.setLocalizedDescription(processInstance.getLocalizedDescription());
dto.setLocalizedName(processInstance.getLocalizedName());
dto.setName(processInstance.getName());
dto.setProcessDefinitionId(processInstance.getProcessDefinitionId());
dto.setProcessDefinitionKey(processInstance.getProcessDefinitionKey());
dto.setProcessDefinitionName(processInstance.getProcessDefinitionName());
dto.setStartTime(processInstance.getStartTime());
dto.setProcessVariables(processInstance.getProcessVariables());
dto.setStartUserId(processInstance.getStartUserId());
dto.setStartTime(processInstance.getStartTime());
dto.setDeploymentId(processInstance.getDeploymentId());
log.info("processInstance.getBusinessKey:{}",processInstance.getBusinessKey());
return dto;
}
任务启动以后,查看数据库表:
我们请求参数设置了两个人名(两个流程变量):通过流程实例id查询 act_ru_variable
表,可以看到新增了两条数据

act_ru_task
表 通过流程实例id查询。因为待执行节点只有一个,所以就只有一条数据(任务处理以后会被删除,添加下一个节点的数据)

查询待办任务
@Override
public List<TaskDTO> taskList(String userId,String processInstanceId) {
TaskQuery taskQuery = taskService.createTaskQuery();
if(StringUtils.isNotBlank(userId)){
taskQuery.taskCandidateOrAssigned(userId);
}
if(StringUtils.isNotBlank(processInstanceId)){
taskQuery.processInstanceId(processInstanceId);
}
List<Task> resultList = taskQuery.orderByTaskCreateTime().desc().list();
List<TaskDTO> list = new ArrayList<>();
for(Task task : resultList) {
TaskDTO dto = new TaskDTO();
dto.setId(task.getId());
dto.setAssignee(task.getAssignee());
dto.setTaskDefinitionKey(task.getTaskDefinitionKey());
dto.setProcessVariables(task.getProcessVariables());
dto.setProcessDefinitionId(task.getProcessDefinitionId());
dto.setProcessInstanceId(task.getProcessInstanceId());
dto.setExecutionId(task.getExecutionId());
dto.setName(task.getName());
dto.setDescription(task.getDescription());
dto.setOwner(task.getOwner());
dto.setTaskLocalVariables(task.getTaskLocalVariables());
dto.setCategory(task.getCategory());
dto.setDueDate(task.getDueDate());
dto.setDelegationState(task.getDelegationState());
dto.setFormKey(task.getFormKey());
dto.setIsSuspended(task.isSuspended());
dto.setParentTaskId(task.getParentTaskId());
dto.setPriority(task.getPriority());
list.add(dto);
}
return list;
}
{
"code": 200,
"message": "成功",
"data": [
{
"id": "300022",
"name": "提交出差申请",
"processInstanceId": "300014",
"description": null,
"taskLocalVariables": {},
"priority": 50,
"owner": null,
"assignee": "小红",
"delegationState": null,
"dueDate": null,
"category": null,
"parentTaskId": null,
"tenantId": null,
"formKey": null,
"isSuspended": false,
"taskDefinitionKey": "sid-cfe6c629-47ed-46e2-9f73-cededa30489e",
"processVariables": {},
"processDefinitionId": "出差-chuchai:6:300004",
"executionId": "300019"
}
],
"success": true
}
处理任务
//{
// "processInstanceId": "300014",
// "taskId": "300022",
// "username": "小红"
//
//}
@Override
@Transactional(rollbackFor = Exception.class)
public void completeTask(CompleteVO vo) {
//校验用户是否拥有处理这个任务的权限
Task task = taskService.createTaskQuery().taskId(vo.getTaskId()).taskAssignee(vo.getUsername()).singleResult();
if(Objects.isNull(task)){
throw new BaseException("任务不存在或您不是当前任务处理人");
}
//添加备注
taskService.addComment(vo.getTaskId(),vo.getProcessInstanceId(),"同意");
//处理任务
taskService.complete(vo.getTaskId(),vo.getVariablesMap());
}
小红的任务处理完成以后,小明才能查到自己的待办任务
两个人的任务处理完成以后,进入end节点,流程结束。
作者介绍
维维
V1