可以使用插件进行绘制流程图
插件支持.xml,bpmn20.xml,.bpmn三种格式的文件
如果不支持则可以在idea中进行配置
image.png

新建

在resource/bpmn 目录上右键新建bpmn文件
image.png

1、绘制流程定义

在生成的文件上或者打开的文件中右键使用插件预览
image.png

在新打开的窗口中进行绘制流程

image.png

绘制中需要设置一些属性
image.png

结果

image.png
查看源码
image.png
导出为png格式的图片
image.png

指定的节点负责人【woker】【manager】【financer】

2、部署

通用上传部署

将流程定义文件和导出的png文件上传进行部署

  1. /**
  2. * 分别上传流程定义文件和流程示意图进行部署
  3. */
  4. @Test
  5. void testDeploy() {
  6. // 创建processEngine
  7. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
  8. // 获取RepositoryService实例
  9. RepositoryService repositoryService = processEngine.getRepositoryService();
  10. // 使用repositoryService进行部署
  11. Deployment deployment = repositoryService.createDeployment()
  12. .addClasspathResource("bpmn/Leave-1.bpmn20.xml")//添加流程定义文件
  13. .addClasspathResource("bpmn/Leave-1.png")//添加流程png资源
  14. .name("员工请假流程Leave")//定义部署名称
  15. .deploy();
  16. // 输出部署信息
  17. log.info("流程部署id:{}", deployment.getId());
  18. log.info("流程部署名称:{}", deployment.getName());
  19. }

部署会将该流程的部署信息插入【act_re_deployment】数据表中
image.png
并生成 一个流程定义信息插入【act_re_procdef】数据表中
image.png
上传的文件存储在【act_ge_bytearray】数据表中
image.png
一个deploy可以对应多个procdef信息
建议一个deploy对应一个procdef
部署完成:
image.png

zip压缩包部署

可以一次性部署多个流程,png文件名称需要和流程定义文件的id进行一一对应
activiti对于图片文件只支持【png|jpg|gif|svg】四种格式
对于流程定义文件支持【.xml|.bpmn20.xml|.bpmn】三种格式
将流程定义文件和导出的png文件打包成为压缩包上传进行部署

  1. /**
  2. * 将流程文件和图片打包一起部署
  3. */
  4. @Test
  5. void deploymentsByZip() {
  6. // 定义上传文件流
  7. InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/Leave-1.zip");
  8. ZipInputStream zipInputStream = new ZipInputStream(inputStream);
  9. // 创建processEngine
  10. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
  11. // 获取RepositoryService实例
  12. RepositoryService repositoryService = processEngine.getRepositoryService();
  13. // 使用repositoryService进行部署
  14. Deployment deployment = repositoryService.createDeployment()
  15. .addZipInputStream(zipInputStream)
  16. .deploy();
  17. // 输出部署信息
  18. log.info("流程部署id:{}", deployment.getId());
  19. log.info("流程部署名称:{}", deployment.getName());
  20. }

3、启动流程实例

根据流程文件定义的id进行启动流程实例
注意不是部署id而是流程文件定义的id

  1. /**
  2. * 启动流程实例
  3. */
  4. @Test
  5. void testStartProcess() {
  6. // 创建ProcessEngine
  7. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
  8. // 获取RuntimeService
  9. RuntimeService runtimeService = processEngine.getRuntimeService();
  10. // 根据流程定义id进行启动流程
  11. String key = "Leave-1";
  12. ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key);
  13. // 输出启动信息
  14. log.info("流程定义id:{}", processInstance.getProcessDefinitionId());
  15. log.info("流程实例id:{}", processInstance.getId());
  16. log.info("当前活动id:{}", processInstance.getActivityId());
  17. }

执行之后依次插入以下七张数据表中
image.png
历史信息:【ACT_HI_TASKINST】【ACT_HI_PROCINST】【ACT_HI_ACTINST】【ACT_HI_IDENTITYLINK】
运行时:【ACT_RU_EXECUTION】【ACT_RU_TASK】【ACT_RU_IDENTITYLINK】
image.png

启动实例后,相对应权限的用户就可以通过该实例提出相对应的流程工单了

4、流程节点任务相关

查询任务列表

private final String processDefinitionKey = "Leave-1";

    /**
     * 任务负责人 worker 在正式开发中就是查询的用户名
     */
    private final String assignee_worker = "worker";

    private final String assignee_manager = "manager";

    private final String assignee_finance = "financer";

    /**
     * 查询当前个人待执行任务
     */
    @Test
    void testFindTaskList() {
        //    创建taskService
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        //    根据流程key【流程定义ID】 和任务负责人查询任务列表
        TaskQuery taskQuery = taskService.createTaskQuery().processDefinitionKey(processDefinitionKey);
        //指定任务负责人
        List<Task> workerList = taskQuery.taskAssignee(assignee_worker).list();
        List<Task> managerList = taskQuery.taskAssignee(assignee_manager).list();
        List<Task> financeList = taskQuery.taskAssignee(assignee_finance).list();
        //    输出信息
        log.info("=================worker===============");
        log.info("worker待执行任务:{}个", workerList.size());
        for(Task task : workerList) {
            log.info("流程实例id:{}", task.getProcessInstanceId());
            log.info("任务id:{}", task.getId());
            log.info("任务负责人:{}", task.getAssignee());
            log.info("任务名称:{}", task.getName());
        }
        log.info("=================manager===============");
        log.info("manager待执行任务:{}个", managerList.size());
        for(Task task : managerList) {
            log.info("流程实例id:{}", task.getProcessInstanceId());
            log.info("任务id:{}", task.getId());
            log.info("任务负责人:{}", task.getAssignee());
            log.info("任务名称:{}", task.getName());
        }
        log.info("=================finance===============");
        log.info("finance待执行任务:{}个", financeList.size());
        for(Task task : financeList) {
            log.info("流程实例id:{}", task.getProcessInstanceId());
            log.info("任务id:{}", task.getId());
            log.info("任务负责人:{}", task.getAssignee());
            log.info("任务名称:{}", task.getName());
        }
    }

image.png

完成任务


    private final String processDefinitionKey = "Leave-1";

    /**
     * 任务负责人 worker 在正式开发中就是查询的用户名
     */
    private final String assignee_worker = "worker";

    private final String assignee_manager = "manager";

    private final String assignee_finance = "financer";


    /**
     * 根据查询出来的任务id进行完成任务
     */
    @Test
    void testTaskCompleteByWorker() {
        //    获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //    获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //    根据流程定义key和用户名查询任务,返回一个任务对象
        Task task = taskService.createTaskQuery()
                               .processDefinitionKey(processDefinitionKey)
                               .taskAssignee(assignee_worker)
                               .singleResult();
        if(task == null) {
            log.info("worker无待执行任务");
            return;
        }
        //    根据任务id完成任务
        taskService.complete(task.getId());
        log.info("worker{}任务完成", task.getId());
    }

    @Test
    void testTaskCompleteByManager() {
        //    获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //    获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //    根据流程定义key和用户名查询任务,返回一个任务对象
        Task task = taskService.createTaskQuery()
                               .processDefinitionKey(processDefinitionKey)
                               .taskAssignee(assignee_manager)
                               .singleResult();
        if(task == null) {
            log.info("manager无待执行任务");
            return;
        }
        //    根据任务id完成任务
        taskService.complete(task.getId());
        log.info("manager{}任务完成", task.getId());
    }

    @Test
    void testTaskCompleteByFinance() {
        //    获取processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //    获取TaskService
        TaskService taskService = processEngine.getTaskService();
        //    根据流程定义key和用户名查询任务,返回一个任务对象
        Task task = taskService.createTaskQuery()
                               .processDefinitionKey(processDefinitionKey)
                               .taskAssignee(assignee_finance)
                               .singleResult();
        if(task == null) {
            log.info("finance无待执行任务");
            return;
        }
        //    根据任务id完成任务
        taskService.complete(task.getId());
        log.info("finance{}任务完成", task.getId());
    }

任务会根据流程节点节点指定进行递进
依次执行完之后在进行查询任务
image.png


image.png


image.png


image.png

任务执行完毕


5、查询任务

查询流程定义

查询一个文件之中定义了几个流程定义实例

    /**
     * 查询一个文件中有几个流程定义
     */
    @Test
    void queryProcessDefinition() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.processDefinitionKey("Leave-1").list();
        for(ProcessDefinition processDefinition : processDefinitionList) {
            log.info("流程定义id:{}",processDefinition.getId());
            log.info("流程定义name:{}",processDefinition.getName());
            log.info("流程定义key:{}",processDefinition.getKey());
            log.info("流程定义version:{}",processDefinition.getVersion());
            log.info("流程部署id:{}",processDefinition.getDeploymentId());
        }
    }

image.png

查询流程实例

查询当前定义流程下有几个流程实例

     /**
     * 查询当前的流程定义中有几个流程实例运行
     */
    @Test
    void queryProcessInstance() {
        String key = "Leave-1";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery().processDefinitionKey(key).list();
        for(ProcessInstance processInstance : processInstanceList) {
            log.info("流程实例id:{}",processInstance.getProcessInstanceId());
            log.info("所属流程定义id:{}",processInstance.getProcessDefinitionId());
            log.info("是否执行完毕:{}",processInstance.isEnded());
            log.info("是否暂停执行:{}",processInstance.isSuspended());
            log.info("当前活动标识:{}",processInstance.getActivityId());
            log.info("业务关键字:{}",processInstance.getBusinessKey());
        }
    }

查询历史信息

    /**
     * 查询当前的流程定义中有几个流程实例运行
     */
    @Test
    void queryHistoryInfo() {
        String key = "Leave-1";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        HistoryService historyService = processEngine.getHistoryService();
        //获取actinst的查询对象
        HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
        //查询act_hi_actinst 表 根据InstanceId 进行查询,查询一个流程的所有历史信息
        instanceQuery.processInstanceId("2501");
        //查询act_hi_actinst 表 根据DefinitionId进行查询,查询一个流程的所有历史信息
        instanceQuery.processDefinitionId("Leave-1:1:4");
        //排序 根据开始时间排序
        instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
        //查询所有的list
        List<HistoricActivityInstance> historicProcessInstanceList = instanceQuery.list();
        //输出信息
        for(HistoricActivityInstance instance : historicProcessInstanceList) {
            log.info("当前活动标识:{}", instance.getActivityId());
            log.info("当前活动名称:{}", instance.getActivityName());
            log.info("所属流程定义id:{}", instance.getProcessDefinitionId());
            log.info("所属流程实例id:{}", instance.getProcessInstanceId());
            System.out.println("==============================================");
        }
    }

image.png

6、其他操作

删除流程部署

    /**
     * 删除流程部署
     */
    @Test
    void deleteDeployment() {
        String deployId = "1";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //删除流程定义,如果该部署已有流程实例启动则删除报错
        repositoryService.deleteDeployment(deployId);
        //删除流程定义,设置true,级联删除即使该部署已有流程实例启动也可以删除,同时删除日志
        //repositoryService.deleteDeployment(deployId,true);
    }

导出流程定义

     /**
     * 查询已有的bpmn信息
     *
     * @throws Exception
     */
    @Test
    void queryBpmnFiles() throws Exception {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                                                               .processDefinitionKey("Leave-1")
                                                               .singleResult();
        //获取部署id
        String deploymentId = processDefinition.getDeploymentId();
        //    通过方法读取数据库中的文件信息
        InputStream pngInput = repositoryService.getResourceAsStream(deploymentId,
                                                                     processDefinition.getDiagramResourceName());
        InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId,
                                                                      processDefinition.getResourceName());

        //    导出文件
        File png = new File("d:/Leave.png");
        File bpmn = new File("d:/Leave.bpmn20.xml");

        FileOutputStream pngOut = new FileOutputStream(png);
        FileOutputStream bpmnOut = new FileOutputStream(bpmn);
        //输入流和输出流的转换
        IoUtil.copy(pngInput, pngOut);
        IoUtil.copy(bpmnInput, bpmnOut);

        //关闭流
        pngOut.close();
        bpmnOut.close();
        pngInput.close();
        bpmnInput.close();
    }

总结:

附录: