🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
:-: ![](https://img.kancloud.cn/c4/7e/c47e7faf15f85562f56d910b83e1605e_1156x215.png) *本小节的源码:/activiti-01/src/test/java/-/ActivitiDemo* 下面演示上图流程操作过程,步骤如下: [TOC] # 1. 流程定义 **1. 绘制流程图** 根据【流程设计器的使用】一节我已经画出了上面的流程图。 一个`.bpmn`文件可以定义多个流程,不过我们建议每个文件只包含一个流程定义, 可以简化开发过程中的维护难度。 **2. 将流程图的`.bpmn`文件导出为`.png`图片** (1)将`.bpmn`后缀改成`.xml`后缀。 ![](https://img.kancloud.cn/e7/e3/e7e30caa14edac0bc30d9d8e525e03c9_1457x543.png) (2)使用流程设计器打开`.xml`文件。 ![](https://img.kancloud.cn/fd/74/fd746da750a1c84778917dd05b652821_1296x788.png) (3)导出为图片,保存到`resources`目录下。 ![](https://img.kancloud.cn/63/8c/638c720a93b8fd67a8e2c37a1e2d2972_1728x484.png) (4)再将`.xml`后缀改回`.bpmn`后缀。 <br/> # 2. 流程部署 流程部署就是把流程图的相关数据保存到数据库中。 **部署方式1:单个文件部署** ```java @Test public void testDeployment() { //1、创建ProcessEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2、获取RepositoryServcie RepositoryService repositoryService = processEngine.getRepositoryService(); //3、使用service进行流程的部署,定义一个流程的名字,把bpmn和png部署到数据中 Deployment deploy = repositoryService.createDeployment() .name("出差申请流程") .addClasspathResource("bpmn-02/evection.bpmn") .addClasspathResource("bpmn-02/image/evection.png") .deploy(); //4、输出部署信息 System.out.println("流程部署id=" + deploy.getId()); //id为数据库中随机分配的id System.out.println("流程部署名字=" + deploy.getName());//名字就是上面name("出差申请流程")设置的名字 } ``` **部署方式2:压缩包文件部署** ```java @Test public void deployProcessByZip() { //获取流程引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //获取RepositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); //读取资源包文件,构造成inputStream InputStream inputStream = this.getClass() .getClassLoader() .getResourceAsStream("bpmn-02/evection.zip"); //用inputStream 构造ZipInputStream ZipInputStream zipInputStream = new ZipInputStream(inputStream); //使用压缩包的流进行流程的部署 Deployment deploy = repositoryService.createDeployment() .name("出差申请流程") .addZipInputStream(zipInputStream) .deploy(); System.out.println("流程部署id=" + deploy.getId()); System.out.println("流程部署的名称=" + deploy.getName()); } ``` <br/> 完成上面的部署后我们到数据库中查看主要的3张表。 ```sql -- 流程定义部署表:每部署一次增加一条记录,即运行上面的部署程序一次,记录就增加一条记录 mysql> select * from act_re_deployment; +-----+--------------+-----------+------+------------+---------------------+-----------------+ | ID_ | NAME_ | CATEGORY_ | KEY_ | TENANT_ID_ | DEPLOY_TIME_ | ENGINE_VERSION_ | +-----+--------------+-----------+------+------------+---------------------+-----------------+ | 1 | 出差申请流程 | NULL | NULL | | 2021-10-09 14:57:27 | NULL | +-----+--------------+-----------+------+------------+---------------------+-----------------+ -- 流程定义表:部署每个新的流程定义都会在这张表中增加一条记录 -- 注意,KEY_ 这个字段是用来唯一识别不同流程的关键字 mysql> select * from act_re_procdef; +----------------+------+------------------------------+--------------+------------+----------+----------------+-----------------------+... | ID_ | REV_ | CATEGORY_ | NAME_ | KEY_ | VERSION_ | DEPLOYMENT_ID_ | RESOURCE_NAME_ | DGRM_... +----------------+------+------------------------------+--------------+------------+----------+----------------+-----------------------+... | myEvection:1:4 | 1 | http://www.activiti.org/test | 出差申请流程 | myEvection | 1 | 1 | bpmn-02/evection.bpmn | NULL ... +----------------+------+------------------------------+--------------+------------+----------+----------------+-----------------------+... -- 流程资源表 mysql> select id_, rev_, name_, deployment_id_, left(bytes_, 30) as bytes_, generated_ from act_ge_bytearray; +-----+------+----------------------------+----------------+--------------------------------+------------+ | id_ | rev_ | name_ | deployment_id_ | bytes_ | generated_ | +-----+------+----------------------------+----------------+--------------------------------+------------+ | 2 | 1 | bpmn-02/evection.bpmn | 1 | <?xml version="1.0" encoding=" | 0 | | 3 | 1 | bpmn-02/image/evection.png | 1 | Binary/Image | 0 | +-----+------+----------------------------+----------------+--------------------------------+------------+ act_re_deployment和act_re_procdef一对多关系,一次部署在流程部署表生成一条记录, 但一次部署可以部署多个流程定义,每个流程定义在流程定义表生成一条记录。 每一个流程定义在act_ge_bytearray会存在两个资源记录,bpmn和png。 建议:一次部署一个流程,这样部署表和流程定义表是一对一有关系,方便读取流程部署及流程定义信息。 ``` <br/> # 3. 启动流程 ```java /** * 启动流程实例,将会依次调用下面的表,每次运行该程序就会创建一个流程实例 * `act_hi_actinst` 流程实例执行历史信息 * `act_hi_identitylink` 流程参与用户的历史信息 * `act_hi_procinst` 流程实例的历史信息 * `act_hi_taskinst` 流程任务的历史信息 * `act_ru_execution` 流程执行信息 * `act_ru_identitylink` 流程的正在参与用户信息 * `act_ru_task` 流程当前任务信息 */ @Test public void testStartProcess() { //1、创建ProcessEngine ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2、获取RunTimeService RuntimeService runtimeService = processEngine.getRuntimeService(); //3、根据流程定义的id启动流程 ProcessInstance instance = runtimeService.startProcessInstanceByKey("myEvection"); //4、输出内容 System.out.println("流程定义ID:" + instance.getProcessDefinitionId()); //myEvection:1:4 System.out.println("流程实例ID:" + instance.getId()); //2501 System.out.println("当前活动的ID:" + instance.getActivityId()); //null } ``` # 4. 查询个人待执行任务 ```java /** * 查询个人待执行的任务,注意查询的是未完成的任务 */ @Test public void testFindPersonalTaskList() { //1、获取流程引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2、获取taskService TaskService taskService = processEngine.getTaskService(); //3、根据流程key 和 任务的负责人 查询任务 List<Task> taskList = taskService.createTaskQuery() .processDefinitionKey("myEvection") //流程Key .taskAssignee("张三") //要查询的负责人 .list(); //4、输出 for (Task task : taskList) { System.out.println("流程实例id=" + task.getProcessInstanceId()); System.out.println("任务Id=" + task.getId()); System.out.println("任务负责人=" + task.getAssignee()); System.out.println("任务名称=" + task.getName()); System.out.println(); } ////循环输出如下 //流程实例id=12501 //任务Id=12505 //任务负责人=张三 //任务名称=创建出差申请 } ``` # 5. 完成个人任务 ```java /** * 完成个人任务 * 根据流程图任务的执行顺序为:张三->李四->王五->赵六 */ @Test public void completTask() { //获取引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //获取操作任务的服务 TaskService TaskService taskService = processEngine.getTaskService(); //查询张三待完成的任务 Task task = taskService.createTaskQuery() .processDefinitionKey("myEvection") .taskAssignee("张三") //按照该顺序 张三->李四->王五->赵六 依次更换参数便可按照顺序完成每个人的任务 .singleResult(); System.out.println("流程实例id=" + task.getProcessInstanceId()); //12501 System.out.println("任务Id=" + task.getId()); //12505 System.out.println("任务负责人=" + task.getAssignee()); //张三 System.out.println("任务名称=" + task.getName()); //创建出差申请 //根据任务ID来完成对应的任务,张三->李四->王五->赵六 //完成任务后,再调用上面的查询任务查询就查不到了 taskService.complete(task.getId()); } ``` # 6. 其他操作 ```java /** * 查询流程定义 * 包含流程定义,流程部署,流程定义版本 */ @Test public void queryProcessDefinition() { //获取引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //获取Repositoryservice RepositoryService repositoryService = processEngine.getRepositoryService(); //获取ProcessDifinitionQuery对象 ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery(); //查询当前所有的流程定义 ,返回流程定义信息的集合 List<ProcessDefinition> definitionList = definitionQuery.processDefinitionKey("myEvection") .orderByProcessDefinitionVersion() //通过版本排序 .desc() //倒序 .list(); //输出信息 for (ProcessDefinition processDefinition : definitionList) { System.out.println("流程定义ID:" + processDefinition.getId()); System.out.println("流程定义名称:" + processDefinition.getName()); System.out.println("流程定义Key:" + processDefinition.getKey()); System.out.println("流程定义版本:" + processDefinition.getVersion()); System.out.println("流程部署ID:" + processDefinition.getDeploymentId()); } //流程定义ID:myEvection:1:4 //流程定义名称:出差申请流程 //流程定义Key:myEvection //流程定义版本:1 //流程部署ID:1 } /** * 删除流程部署信息,会根据部署表act_re_deployment中的部署ID_来删除下面三张表有关该记录的数据 * `act_ge_bytearray` * `act_re_deployment` * `act_re_procdef` * 1) 使用repositoryService删除流程定义,历史表信息不会被删除 * 2)如果该流程定义下没有正在运行的流程,则可以用普通删除。如果该流程定义下存在已经运行的流程, * 使用普通删除报错,可用级联删除方法将流程及相关记录全部删除。 * 先删除没有完成流程节点,最后就可以完全删除流程定义信息 * 项目开发中级联删除操作一般只开放给超级管理员使用. */ @Test public void deleteDeployMent() { //获取流程引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //通过引擎来获取 RepositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); //通过部署id来删除流程部署信息 String deploymentId = "1"; //repositoryService.deleteDeployment(deploymentId); 非级联删除 //设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式,如果流程 repositoryService.deleteDeployment(deploymentId, true); } /** * 下载资源文件 * 需要引入如下依赖 * <dependency> * <groupId>commons-io</groupId> * <artifactId>commons-io</artifactId> * <version>2.6</version> * </dependency> * <p> * 方案1: 使用Activiti提供的api,来下载资源文件,保存到文件目录 * 方案2: 自己写代码从数据库中下载文件,使用jdbc对blob 类型,clob类型数据读取出来,保存到文件目录 * 这里我们使用方案1,Activiti提供的api:RespositoryService */ @Test public void getDeployment() throws IOException { //1、得到引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2、获取api,RepositoryService RepositoryService repositoryService = processEngine.getRepositoryService(); //3、获取查询对象 ProcessDefinitionQuery查询流程定义信息 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionKey("myEvection") .singleResult(); //4、通过流程定义信息,获取部署ID String deploymentId = processDefinition.getDeploymentId(); //5、获取png图片的流 //从流程定义表中,获取png图片的目录和名字 //提醒:bpmn-02/evection.bpmn,bpmn-02/image/evection.png,则在这里获取不到图片的名字 String pngName = processDefinition.getDiagramResourceName(); //InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName); InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, "bpmn-02/image/evection.png"); //6、获取bpmn的流 String bpmnName = processDefinition.getResourceName(); InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName); //7、构造OutputStream流 File pngFile = new File("e:/evectionflow01.png"); File bpmnFile = new File("e:/evectionflow01.bpmn"); FileOutputStream pngOutStream = new FileOutputStream(pngFile); FileOutputStream bpmnOutStream = new FileOutputStream(bpmnFile); //8、输入流,输出流的转换 IOUtils.copy(pngInput, pngOutStream); IOUtils.copy(bpmnInput, bpmnOutStream); //9、关闭流 pngOutStream.close(); bpmnOutStream.close(); pngInput.close(); bpmnInput.close(); } /** * 查看历史信息 */ @Test public void findHistoryInfo() { //获取引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //获取HistoryService HistoryService historyService = processEngine.getHistoryService(); //获取 actinst表的查询对象 HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery(); //查询 actinst表,条件:根据 InstanceId 查询 //instanceQuery.processInstanceId("2501"); //查询 actinst表,条件:根据 DefinitionId 查询 instanceQuery.processDefinitionId("myEvection:1:4"); //增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序 instanceQuery.orderByHistoricActivityInstanceStartTime().asc(); //查询所有内容 List<HistoricActivityInstance> activityInstanceList = instanceQuery.list(); //输出 for (HistoricActivityInstance hi : activityInstanceList) { System.out.println(hi.getActivityId()); System.out.println(hi.getActivityName()); System.out.println(hi.getProcessDefinitionId()); System.out.println(hi.getProcessInstanceId()); System.out.println("<==========================>"); } //_2 //StartEvent //myEvection:1:4 //12501 //<==========================> //_3 //创建出差申请 //myEvection:1:4 //12501 //<==========================> //_5 //部门经理审批 //myEvection:1:4 //12501 //<==========================> } ``` 下载的资源文件如下: ![](https://img.kancloud.cn/43/88/4388229459dcf5936edc0cd997ad905f_1298x386.png)