维维

V1

2023/03/23阅读:33主题:默认主题

从一个简单的小流程开始

从一个简单的小流程开始

整合好基础框架以后,就可以开始实现简单的流程

生成BPMN xml文件(制作流程图)

  • idea插件

    1. idea安装插件
  1. 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>
  1. 打开文件,鼠标右键点击
  1. 弹出工具窗口,然后邮件点击空白开始制作流程图
  1. 绘制出差流程图。

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节点,流程结束。

分类:

后端

标签:

Java

作者介绍

维维
V1