• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
打工人丶
博客园    首页    新随笔    联系   管理    订阅  订阅

activity入门教程

视频:https://www.bilibili.com/video/BV1ge4y1378c?p=34&spm_id_from=pageDriver&vd_source=61b6fb4e547748656e36b17ee95125fb

1. 什么是工作流

工作流:就是通过计算机对业务流程自动化执行进行管理。

    它主要解决的是:使在多个参与者之间按照某种预定义的规则☆☆☆☆☆自动进行传递☆☆☆☆☆文档、信息或任务的过程。

    例如:员工的请假,出差,外出采购,合同审核等等,这些过程,都是一个工作流。






2. 为什么要使用工作流

不使用工作流:

    对于工作流的处理,如果采用原始的方式,我们需要拿着各种文件到各个负责人那里去签字,需要在多个部门之间不断审批,这种方式费时费力。

    例如:填写请假单->部门经理审批->总经理审批->人事备案。

    要实现上述的流程,我们自己可以通过字段标识来实现这个审批效果,在业务表中加个字段,比如填写请假单用1标识,部门经理用2标识,总经理用3标识,人事备案用4标识,好像看起来没啥问题,也实现了审批效果。

    可是一旦我们的流程出现了变化,这个时候我们就需要改动我们的代码了,这显然是不可取的,特别麻烦。

使用工作流:

    工作流引擎实现了一个规范,这个规范要求我们的流程管理与状态字段无关,始终都是读取业务流程图的下一个节点。

    当业务更新的时候我们只需要更新业务流程图就行了。这就实现了业务流程改变,不用修改代码。






3. 常见的工作流

主流的框架有:Activiti、jBPM、Camunda 、Flowable







4. Activiti介绍

activiti是一个工作流引擎,可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言BPMN进行定义,业务流程按照预先定义的流程进行执行。

官方网站:https://www.activiti.org







5. BPMN介绍

BPMN:即业务流程模型和符号,是一套标准的业务流程建模符号,使用 BPMN 提供的符号可以创建业务流程。Activit 就是使用 BPMN 进行流程建模、流程执行管理的。


BPMN 使用一些符号来明确业务流程设计流程图的一套符号规范,能增进业务建模时的沟通效率。







6. Activty使用流程

  1. 引入依赖
  2. 绘制流程模型
  3. 流程部署(使用 activiti 提供的 api 向 activiti 中部署.bpmn 文件)
  4. 启动一个流程实例(启动一个流程实例就好比new一个java对象)
  5. 用户查询待办任务
  6. 用户办理任务
  7. 流程结束






7. Activty入门实战体验

7.3 启动项目

启动项目,即可生成项目数据库表


7.4 数据库表介绍

Activiti 的运行支持必须要有这 25 张表的支持。


表的命名规则和作用介绍:
Activiti 的表都以 act_ 开头,紧接着是表示表的用途的两个字母标识,也和 Activiti 所提供的服务的 API 对应。

  • ACT_RE:RE 表示 repository,这个前缀的表包含了流程定义和流程静态资源 (图片、规则、等等)

  • ACT_RU:RU 表示 runtime,这些表运行时,会包含流程实例、任务、变量、异步任务等流程业务进行中的数据。Activiti 只在流程实例执行过程中保存这些数据,在流程结束时就会删除这些记录。

  • ACT_HI: HI 表示 history,这些表包含一些历史数据,比如历史流程实例、变量、任务等等

  • ACT_GE:GE 表示 general,通用数据







Activiti常用Service服务接口介绍:
在activiti中,除了25张表外,还提供了 Service 服务层供我们使用,在项目中直接使用服务层接口,就能实现工作流相关的业务功能。

  • RepositoryService【仓储服务】

    Activiti 的资源管理类,该服务负责部署流程定义,管理流程资源。
    在使用 Activiti 时,一开始需要先完成流程部署,即将使用建模工具设计的业务流程图通过 RepositoryService 进行部署。


  • RuntimeService【运行时服务】

    Activiti 的流程运行管理类,该服务用于开始一个新的流程实例,获取关于流程执行的相关信息。
    流程定义用于确定一个流程中的结构和各个节点间行为,而流程实例则是对应的流程定义的一个执行,可以理解为 Java 中类和对象的关系。


  • TaskService【任务服务】

    Activiti 的任务管理类,用于处理业务运行中的各种任务。
    例如查询分给用户或组的任务、创建新的任务、分配任务、确定和完成一个任务。


  • HistoryService

    Activiti 的历史管理类,该服务可以查询历史信息。在执行流程工程中,引擎会保存很多数据。
    比如流程实例启动时间、任务的参与者、完成任务的时间、每个流程实例的执行路径等等。这个服务主要通过查询功能来获得这些数据。


  • ManagementService

    Activiti 的引擎管理类,该服务提供了对 Activiti 流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用。
    主要用于 Activiti 系统的日常维护。


7.4 流程定义部署

	// 部署流程图
	@Test
	public void test2() {
		ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
		
		RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
		DeploymentBuilder builder = repositoryService.createDeployment();
		Deployment deploy = builder
			.addClasspathResource("bpmn/leave.bpmn")
			.addClasspathResource("bpmn/leave.png")
			.disableSchemaValidation()
			.name("请求")
			.deploy();
		
		System.out.println("流程部署的id:" + deploy.getId()); // 流程ID:10001
		System.out.println("流程name:" + deploy.getName()); // 流程name:请假
	}

流程定义部署后,会操作activiti的3张表如下:
    act_re_deployment     流程定义部署表,每部署一次增加一条记录
    act_re_procdef        流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
    act_ge_bytearray      流程资源表 

7.5 创建流程实例

	// 创建(启动)流程实例
	@Test
	public void test3() {
		ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
		
		// 获取流程部署信息
		ProcessDefinition result = defaultProcessEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId("10001").singleResult();
		String id = result.getId();
		String key = result.getKey();
		System.out.println("流程定义ID:" + id);  // 流程定义ID:myProcess_1:1:10004
		System.out.println("流程定义KEY:" + key);  // 流程定义KEY:myProcess_1
		
		RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
		ProcessInstance processInstance = runtimeService.startProcessInstanceById(result.getId());// 根据流程定义的ID创建流程实例
		//runtimeService.startProcessInstanceByKey() // 根据流程定义的KEY创建流程实例
		System.out.println(processInstance);
	}

7.4的 流程定义:将bpmn文件放到activiti的三张表中,好比是java中的一个类。
7.5的 流程实例:好比是java中的一个对象

(一个流程定义可以对应多个流程实例)


启动流程实例后,会操作activiti的4张表如下:
    act_hi_actinst            流程实例执行历史
    act_hi_identitylink       流程的参与用户历史信息
    act_hi_procinst           流程实例历史信息
    act_hi_taskinst           流程任务历史信息
    act_ru_execution          流程执行信息
    act_ru_identitylink       流程的参与用户信息
    act_ru_task               任务信息

7.6 查询任务

	// 查询任务
	@Test
	public void test4() {
		ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
		
		// 查询任务
		TaskService taskService = defaultProcessEngine.getTaskService();
		List<Task> tasks = taskService.createTaskQuery().processDefinitionId("myProcess_1:1:10004").taskAssignee("zhangsan").list();
		
		for (Task task : tasks) {
			String processDefinitionId = task.getProcessDefinitionId(); // 流程定义ID
			String processInstanceId = task.getProcessInstanceId(); // 流程实例ID
			String taskDefinitionKey = task.getTaskDefinitionKey(); // 任务定义Key
			String name = task.getName(); // 任务名称
			String id = task.getId(); // 任务ID
			
			System.out.println("流程定义ID:"+processDefinitionId); // 流程定义ID:myProcess_1:1:10004
			System.out.println("流程实例ID:"+processInstanceId); // 流程实例ID:12501
			System.out.println("任务定义Key:"+taskDefinitionKey); // 任务定义Key:_3
			System.out.println("任务名称:"+name); // 任务名称:张三审批
			System.out.println("任务ID:"+id); // 任务ID:12505
		}
	}

每个节点都配置了Assignee,流程启动后,任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。


个人任务查询–所涉及到的表如下:
    ACT_RU_TASK表,ACT_RE_PROCDEF表

select 
    distinct RES.* 
FROM 
    ACT_RU_TASK RES INNER JOIN ACT_RE_PROCDEF D
ON 
    RES.PROC_DEF_ID_ = D.ID_
WHERE 
    RES.ASSIGNEE_ = 'zs' and D.KEY_ = 'myJtxx' order by RES.ID_ asc
LIMIT 2147483647 OFFSET 0;


7.7 处理任务

	// 处理任务
	@Test
	public void test5() {
		ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
		
		TaskService taskService = defaultProcessEngine.getTaskService();
		
		Task task = taskService.createTaskQuery().processDefinitionId("myProcess_1:1:10004").taskAssignee("zhangsan").singleResult();
		
		// 完成任务
		taskService.complete(task.getId());  // void complate(String id)  根据任务ID完成任务
	}

完成任务后,任务自动到下一个节点


完成个人任务时会涉及的表如下:
    ACT_RU_TASK                   运行时任务表,就是对于一个流程,已经走到哪个节点了,这个里面保存的就是当前正在走的节点的信息;也就是保存的是当前正在执行的任务;
    ACT_HI_TASKINST               流程任务历史信息 已经执行完成的任务,都会保存在这个里面
    ACT_HI_ACTINST                历史的流程实例
    ACT_HI_IDENTITYLINK           历史的流程运行过程中用户关系
    ACT_RU_EXECUTION              运行时流程执行实例
    ACT_RU_IDENTITYLINK           运行时用户关系信息,存储任务节点与参与者的相关信息 这个是更新操作
    ACT_RU_TASK                   任务信息

7.8 查询已处理任务

	// 查询历史处理任务
	@Test
	public void test6() {
		ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
		
		HistoryService historyService = defaultProcessEngine.getHistoryService();
		
		// 根据节点的开始时间逆序的排序
		List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().processDefinitionId("myProcess_1:1:10004").orderByHistoricActivityInstanceStartTime().desc().list();
		for (HistoricActivityInstance instance : list) {
			System.out.println(instance.getActivityId());
			System.out.println(instance.getActivityName());
			System.out.println(instance.getActivityType());
			System.out.println(instance.getAssignee());
			System.out.println("------------");
		}
	}




_7
EndEvent
endEvent
null
------------
_5
李四
userTask
lisi
------------
_3
张三
userTask
zhangsan
------------
_2
StartEvent
startEvent
null
------------


7.9 流程实例绑定业务id

Activiti提供的数据是针对于该框架所需要的流程控制维护的数据,也就是数据库25张表存放的数据。


但是在业务系统中,业务数据(我们自己的表)如何与Activiti框架进⾏关联?

  通过流程实例数据的BusinessKey字段来实现关联。在创建流程实例时,指明BusinessKey即可。

	// 创建流程实例,关联业务id
	@Test
	public void test7(){
		//1.获得engine对象
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();

		//2.获得RuntimeService对象
		RuntimeService runtimeService = engine.getRuntimeService();

		//3.创建流程实例,并指明业务id (我们自己的业务表)
		ProcessInstance processInstance = runtimeService.startProcessInstanceById("myProcess_1:1:2504","1001");
		System.out.println("流程实例已经创建");
		System.out.println("业务ID:"+processInstance.getBusinessKey());
	}


7.10 删除流程定义

删除流程定义,可以删除有未结束的流程实例的流程定义或者已结束的流程定义。

 @Test
 public void test2(){
     //1.获得engine
     ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();

     //2.获得RepositoryService
     RepositoryService repositoryService = engine.getRepositoryService();

     //3.删除部署的流程,cascade:true,删除正在进⾏的流程实例,否则⽆法删除
     repositoryService.deleteDeployment("2501",true);
 }






8. 流程实例解释

什么是流程实例:

    流程定义ProcessDefinition,
    流程实例ProcessInstance
    他们是Activiti重要的概念,类似于Java类和Java实例的关系。

    启动一个流程实例表示开始一次业务流程的运行。
    比如员工请假流程部署完成,如果张三要请假就可以启动一个流程实例。
    如果李四也要请假,则也启动一个流程实例。

    两个流程的执行互相不影响,就好比定义一个 java 类,实例化两个对象一样

如何获取流程定义:

    获取流程定义的方法,在Activity中,提供了多种查询方法。
    如,你可以使用如下方式来获取:
    // 创建流程定义查询的对象
    ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
    // 通过查询对象构建指定要查找的流程定义的名称
    ProcessDefinition latestProcessDefinition = processDefinitionQuery.processDefinitionName("你的流程标识").latestVersion().singleResult();

    在流程定义(ProcessDefinition)中,常用的属性包括以下内容:
        ID(id): 流程定义的唯一标识符,通常是一个字符串或UUID。
        Key(key): 流程定义的唯一标识键,通常是一个字符串。在启动流程实例时,可以使用流程定义的key来指定要启动的流程。
        名称(name): 流程定义的名称,通常是一个描述性的字符串,用于标识流程的用途或目的。
        版本号(version): 流程定义的版本号,用于区分不同版本的同一流程定义。当对流程定义进行更新时,版本号会递增。
        部署ID(deploymentId): 流程定义所属的部署的唯一标识符。每次部署新的流程定义时,会生成一个新的部署ID。
        资源名称(resourceName): 流程定义的XML资源文件的名称,通常以.bpmn或.bpmn20.xml为扩展名。这个文件包含了流程定义的描述信息。
        部署时间(deploymentTime): 流程定义被部署的时间戳,记录了流程定义的创建时间。
        描述(description): 流程定义的描述信息,通常提供了更详细的说明关于流程定义的用途和功能。

如何启动流程实例:

    启动流程实例,在Activity中,提供了多种重载方法。
    以下是 runtimeService 的部分方法:
        startProcessInstanceByKey(): 通过流程定义的键(Key)来标识要启动的流程。
        startProcessInstanceById(): 通过流程定义的ID来标识要启动的流程。
        startProcessInstanceByMessage(): 根据流程定义中的消息启动新流程实例。






9. 流程挂起与激活

当因为业务需要,将执⾏的流程挂起,或者将已被挂起的流程激活,可以通过Activiti框架,对流程进⾏挂起和激活。

    // 流程挂起
	@Test
	public void test8(){
		//1.获得engine对象
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		
		//2.获得RuntimeService
		RuntimeService runtimeService = engine.getRuntimeService();
		
		//3.获得流程实例对象
		ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId("22501").singleResult();
		
		//4.先判断该流程是否属于正常状态(⾮挂起状态)
		boolean suspended = instance.isSuspended();
		
		if(!suspended){
			//执⾏流程实例的挂起操作
			runtimeService.suspendProcessInstanceById(instance.getId());
			System.out.println(instance.getId()+"流程被挂起");
		}
	}


    // 激活⼀个被挂起的流程
	@Test
	public void test9(){
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		RuntimeService runtimeService = engine.getRuntimeService();
		ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId("22501").singleResult();
		boolean suspended = processInstance.isSuspended();
		if(suspended){
			//当前流程实例已被挂起,激活的操作
			runtimeService.activateProcessInstanceById(processInstance.getId());
			System.out.println(processInstance.getId()+"流程被激活");
		}
	}



9. 任务分配

任务分配:就是将任务分配给指定的负责人。
三种方式:

  1. 固定分配

  2. UEL表达式分配

  3. 监听器分配


9.1 固定分配

业务流程建模时指定固定的任务负责人,如:Assignee:zhangsan



9.2 表达式分配

activiti支持两个UEL表达式:UEL-value和UEL-method。

UEL-value方式:

    /**
     * 启动流程实例
     */
    @Test
    public void startUpProcess01() {
        Map<String, Object> variables = new HashMap<>();
        variables.put("assignee1","zhangsan");

        //创建流程实例,我们需要知道流程定义的key
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("qingjia01", variables);// 启动实例的方法跟之前的方法基本一致,唯一的不同是在启动时,添加了一个参数
        //输出实例的相关信息
        System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例id:" + processInstance.getId());
    }

UEL-method 方式:

    // userBean 是 spring 容器中的一个 bean,表示调用该 bean 的 getUsername(int id)方法。

    // 经理审批:${userBean.getUsername(1)}

    // 人事审批:${userBean.getUsername(2)} 

    @Component
    public class UserBean {

        public String getUsername(int id) {
            if(id == 1) {
                return "zhangsan";
            }
            if(id == 2) {
                return "lisi";
            }
            return "admin";
        }
    }



    /**
     * 启动流程实例
     */
    @Test
    public void startUpProcess02() {
        //创建流程实例,我们需要知道流程定义的key
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("qingjia02");

        //输出实例的相关信息
        System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例id:" + processInstance.getId());
    }

    //启动流程实例,就会调用bean方法,参数为:1,经理审批后,接着调用bean方法,参数为:2






10. 流程变量

10.1 流程变量概念

流程运转有时需要靠流程变量,业务系统和 activiti结合时少不了流程变量,流程变量就是 activiti 在管理工作流时根据管理需要而设置的变量。

比如:在请假申请流程流转时如果请假天数大于2 天则由总经理审核,否则由部门经理直接审核, 请假天数就可以设置为流程变量,在流程流转时使用。



10.2 流程变量的作用域

流程变量的作用可以是一个流程实例,但也可以是一个任务(task)或是一个执行实例。


globa全局变量:

    globa变量:当一个流程变量的作用域为流程实例时,可以称为 global 变量。

    流程变量的默认作用域是流程实例。

global 变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖先设置的变量值。



local局部变量:

    local 变量:任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。

    Local 变量由于在不同的任务或不同的执行实例中,所以,作用域互不影响,变量名可以相同没有影响。


10.3 流程变量的使用方法

流程变量可以用来实现任务分配,也可以在任务与任务之间的连线上使用 UEL表达式 来实现流程的走向。

比如${day > 2 }和${day <= 2},day就是一个流程变量名称,UEL表达式的执行结果是布尔类型。


10.4 设置globa变量

在启动流程时设置流程变量,变量的作用域是整个流程实例。

    @Test
    public void startUpProcess() {
        // ============ 通过 Map<key,value> 设置流程变量,map 中可以设置多个变量,这个 key 就是流程变量的名字 ================
        Map<String, Object> variables = new HashMap<>();
        variables.put("assignee1", "zhangsan");
        variables.put("assignee2", "lisi");

        variables.put("day", "3");

        //创建流程实例,我们需要知道流程定义的key
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("qingjia", variables);

        //输出实例的相关信息
        System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例id:" + processInstance.getId());
    }


10.5 设置local变量

local 流程变量的作用域只在当前任务节点下可用。当进⼊到下⼀个任务时,该局部变量失效。

任务办理时设置local流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无法在当前流程实例使用

    @Test
    public void completLocalTask() {
        Task task = taskService.createTaskQuery().taskAssignee("zhangsan").singleResult();//返回一条

        // 设置local变量,作用域为该任务
        taskService.setVariableLocal(task.getId(), "day", "3");

        // 查看local变量
        System.out.println(taskService.getVariableLocal(task.getId(), "day"));

        //完成任务,参数:任务id
        taskService.complete(task.getId());
    }






11. 任务候选人设置

问题:如果任务负责⼈是单⼀存在的,且任务负责⼈因为默写原因没有办法完成任务,那么流程就没办法执⾏下去了。

解决:可以为任务设置候选⼈,通过候选⼈签收、归还(将签收的任务取消)、执⾏等操作解决单一负责人故障的问题。



11.1 如何设置候选人

	// 部署流程图
	@Test
	public void test10() {
		ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
		
		RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
		DeploymentBuilder builder = repositoryService.createDeployment();
		Deployment deploy = builder
			.addClasspathResource("bpmn/qingjia.bpmn")
			.addClasspathResource("bpmn/qingjia.png")
			.disableSchemaValidation()
			.name("请假")
			.deploy();
		
		System.out.println("流程部署的id:" + deploy.getId()); // 流程部署的id:20001
		System.out.println("流程name:" + deploy.getName()); // 流程name:请假
	}

	
	// 创建(启动)流程实例
	@Test
	public void test11() {
		ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
		
		// 获取流程部署信息
		ProcessDefinition result = defaultProcessEngine.getRepositoryService().createProcessDefinitionQuery().deploymentId("20001").singleResult();
		String id = result.getId();
		String key = result.getKey();
		System.out.println("流程定义ID:" + id);  // 流程定义ID:myProcess_1:2:20004
		System.out.println("流程定义KEY:" + key);  // 流程定义KEY:myProcess_1
		
		RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
		ProcessInstance processInstance = runtimeService.startProcessInstanceById(result.getId());// 根据流程定义的ID创建流程实例
		System.out.println(processInstance);
	}
	

	// 查询任务
	@Test
	public void test12() {
		ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
		
		// 查询任务
		TaskService taskService = defaultProcessEngine.getTaskService();
		List<Task> tasks = taskService.createTaskQuery().processDefinitionId("myProcess_1:2:20004").list();
		
		for (Task task : tasks) {
			String processDefinitionId = task.getProcessDefinitionId(); // 流程定义ID
			String processInstanceId = task.getProcessInstanceId(); // 流程实例ID
			String taskDefinitionKey = task.getTaskDefinitionKey(); // 任务定义Key
			String name = task.getName(); // 任务名称
			String id = task.getId(); // 任务ID
			
			System.out.println("流程定义ID:"+processDefinitionId); // 流程定义ID:myProcess_1:1:10004
			System.out.println("流程实例ID:"+processInstanceId); // 流程实例ID:12501
			System.out.println("任务定义Key:"+taskDefinitionKey); // 任务定义Key:_3
			System.out.println("任务名称:"+name); // 任务名称:张三审批
			System.out.println("任务ID:"+id); // 任务ID:12505
			
			System.out.println("任务负责人:"+task.getAssignee()); // null
			
			List<IdentityLink> list = taskService.getIdentityLinksForTask(task.getId());
			for (IdentityLink identityLink : list) {
				String userId = identityLink.getUserId();
				System.out.println("该任务的任务候选人:" + userId);  // zhangsan lisi
			}
		}
	}

	
	// 候选人lisi 签收任务
	@Test
	public void test13() {
		ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
		
		// 查询任务
		TaskService taskService = defaultProcessEngine.getTaskService();
		List<Task> tasks = taskService.createTaskQuery().processDefinitionId("myProcess_1:2:20004").list();
		
		for (Task task : tasks) {
			String processDefinitionId = task.getProcessDefinitionId(); // 流程定义ID
			String processInstanceId = task.getProcessInstanceId(); // 流程实例ID
			String taskDefinitionKey = task.getTaskDefinitionKey(); // 任务定义Key
			String name = task.getName(); // 任务名称
			String id = task.getId(); // 任务ID
			
			System.out.println("流程定义ID:"+processDefinitionId); // 流程定义ID:myProcess_1:2:20004
			System.out.println("流程实例ID:"+processInstanceId); // 流程实例ID:22501
			System.out.println("任务定义Key:"+taskDefinitionKey); // 任务定义Key:_3
			System.out.println("任务名称:"+name); // 任务名称:发起请假审批
			System.out.println("任务ID:"+id); // 任务ID:22505
			
			System.out.println("任务负责人:"+task.getAssignee()); // null
			
			// lisi签收任务
			String user = "lisi";
			taskService.claim(id, user); // 参数1:任务id   参数2:签收人
			
			// 签收后查询任务负责人
			System.out.println("任务签收后,负责人为:"+task.getAssignee()); // 任务签收后,负责人为:lisi
		}
	}
	

	// 签收后,任务就归给签收人了。
	// 结果候选人lisi 因一些原因现在不能完成该任务,要取消之前的签收操作。【实际上就是将该任务的负责人设置成null】
	@Test
	public void test14() {
		ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
		
		// 查询任务
		TaskService taskService = defaultProcessEngine.getTaskService();
		List<Task> tasks = taskService.createTaskQuery().processDefinitionId("myProcess_1:2:20004").list();
		
		for (Task task : tasks) {
			String processDefinitionId = task.getProcessDefinitionId(); // 流程定义ID
			String processInstanceId = task.getProcessInstanceId(); // 流程实例ID
			String taskDefinitionKey = task.getTaskDefinitionKey(); // 任务定义Key
			String name = task.getName(); // 任务名称
			String id = task.getId(); // 任务ID
			
			System.out.println("流程定义ID:"+processDefinitionId); // 流程定义ID:myProcess_1:2:20004
			System.out.println("流程实例ID:"+processInstanceId); // 流程实例ID:22501
			System.out.println("任务定义Key:"+taskDefinitionKey); // 任务定义Key:_3
			System.out.println("任务名称:"+name); // 任务名称:发起请假审批
			System.out.println("任务ID:"+id); // 任务ID:22505
			
			System.out.println("当前任务负责人:"+task.getAssignee()); // 当前任务负责人:lisi
			
			// lisi要退还任务。【本质就是将责任人设置称null】
			// ★★★★★★★★★  这里你也可以不设置成null,可以将任务转给其他人,如:taskService.setAssignee(task.getId(), zhangsan); 这样就表示将该任务的责任人变成zhangsan  ★★★★★★★★★
			taskService.setAssignee(task.getId(), null); // 参数1:任务ID     参数2:责任人
			
			System.out.println("lisi退还任务后,任务负责人为:" + task.getAssignee()); // lisi退还任务后,任务负责人为:null
		}
	}






11. 网关

网关:用来控制流程的流向。

前面讲过可以通过流程变量来决定走向,这里又说可以通过网关来决定走向。他们之间的区别是什么?

    流程变量决定走向:当出现都不满足的时候,流程就不会继续执行,也不报错。

    网关决定走向:当都不满足的时候,流程就会报错。

网关分类:

  • 排他网关X
  • 并行网关+
  • 包容网关⭕
  • 事件网关


11.1 排他网关

排他网关:只有一条路径会被选择。如果有多个路径同时满足,只会执行第一个满足的。若都不满足,则会报错!



11.2 并行网关

并行网关:所有路径会被同时选择执行。只有当所有路径都执行完毕后,才会执行下一个节点任务。

与排他网关的主要区别是,并行网关不会解析条件。即使顺序流中定义了条件,也会被忽略。

    场景:
        请假申请开始,需要部门经理和总经理都审批,两者没有前后需要两个人全部审批才能进入下个节点人事审批。这个时候就需要并行网关



11.3 包容网关

包容网关:融合了排他网关与并行网关的特点。可以同时执行多条线路,且可以在网关上设置条件。 如果有多个线路同时执行时,只有当所有路径都执行完毕后,才会执行下一个节点任务。

    场景:
        请假申请大于等于2天需要由部门总经理审批,小于2天由部门经理审批,请假申请必须经过人事经理审批。这个时候就需要包容网关







12. springboot整合Activiti

12.1 引入依赖
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring-boot-starter</artifactId>
        <version>7.1.0.M6</version>
    </dependency>

12.2 配置文件

# 应⽤名称
spring.application.name=spring-boot-activiti-demo

# 应⽤服务 WEB 访问端⼝
server.port=8080

# 配置数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/activiti?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=qf123456

# 配置activiti
# true:activiti会对数据库中所有表进⾏更新操作。如果表不存在,则⾃动创建。
# flase: 默认值,activiti在启动时,会对⽐数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。
spring.activiti.database-schema-update=true

# activiti7需要⼿动开启历史记录
spring.activiti.db-history-used=true

# 配置历史记录级别
# none:不保存任何的历史数据,因此,在流程执⾏过程中,这是最⾼效的。
# activity:级别⾼于none,保存流程实例与流程⾏为,其他数据不保存。
# audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
# full:保存历史数据的最⾼级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括⼀些流程参数等。
spring.activiti.history-level=full

12.3 部署bpmn

在resources目录下创建目录:processes。并将流程图bpmn和png复制到该目录下。那么,activiti7框架将会自动进行部署!


12.4 创建流程实例

启动流程实例
   @Test
   public void test2(){
       securityUtil.logInAs("王⼯");
       ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder.start().withProcessDefinitionKey("myProcess_1").build());
       System.out.println("流程实例的id:"+processInstance.getId());
   }

12.5 执行任务

// 完成任务
@Test
public void test3(){
    securityUtil.logInAs("王⼯");

    // 获得当前登陆⽤户的待处理的前10个任务
    Page<Task> tasks = taskRuntime.tasks(Pageable.of(0,10));
    if(tasks!=null && tasks.getTotalItems()>0){
        for (Task task : tasks.getContent()) {
            //执⾏任务
            taskRuntime.complete(TaskPayloadBuilder.complete()
            .withTaskId(task.getId()).build());
            System.out.println("任务执⾏完成");
        }
    }
}
posted @ 2023-11-02 10:58  &emsp;不将就鸭  阅读(483)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3