Activiti7工作流引擎

架构设计

image-20220905101725712

数据表

表前缀规则

  • act_ge_ 通用数据表,ge是general的缩写
  • act_hi_ 历史数据表,hi是history的缩写,对应 HistoryService 接口
  • act_id_ 身份数据表,id是identity的缩写,对应 IdentityService 接口
  • act_re_ 流程存储表,re是repository的缩写,对应 RepositoryService 接口,存储流程部署和流程定义等静态数据
  • act_ru_ 运行时数据表,ru是runtime的缩写,对应 RuntimeService 接口和 TaskService 接口,存储流程实例和用户任务等动态数据

表清单及说明

表分类表名备注说明
一般数据ACT_GE_BYTEARRAY流程定义的bpmn和png文件
ACT_GE_PROPERTY系统相关属性
流程历史记录ACT_HI_ACTINST历史的流程实例
ACT_HI_ATTACHMENT历史的流程附件
ACT_HI_COMMENT历史的说明性信息
ACT_HI_DETAIL历史的流程运行中的细节信息
ACT_HI_IDENTITYLINK历史的流程运行过程中用户关系
ACT_HI_PROCINST历史的流程实例
ACT_HI_TASKINST历史的任务实例
ACT_HI_VARINST历史的流程实例变量表
用户组表ACT_ID_GROUP身份信息-组信息
ACT_ID_INFO身份信息-信息
ACT_ID_MEMBERSHIP身份信息-用户和组关系的中间表
ACT_ID_USER身份信息-用户信息
流程定义表ACT_RE_DEPLOYMENT流程定义部署表
ACT_RE_MODEL模型信息
ACT_RE_PROCDEF流程定义信息
运行实例表ACT_RU_EVENT_SUBSCR运行时事件
ACT_RU_EXECUTION运行时流程执行实例
ACT_RU_IDENTITYLINK运行时参与者的用户信息
ACT_RU_JOB运行时作业
ACT_RU_TASK运行时任务
ACT_RU_VARIABLE流程运行时变量表,记录当前流程可使用的变量,包括 global 和 local

服务接口

service名称service作用
RepositoryServiceactiviti的资源管理类
RuntimeServiceactiviti的流程运行管理类
TaskServiceactiviti的任务管理类
HistoryServiceactiviti的历史管理类
ManagerServiceactiviti的引擎管理类

RepositoryService

是activiti的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此service将流程定义文件的内容部署到计算机。

除了部署流程定义以外还可以:查询引擎中的发布包和流程定义。

暂停或激活发布包,对应全部和特定流程定义。 暂停意味着它们不能再执行任何操作了,激活是对应的反向操作。获得多种资源,像是包含在发布包里的文件, 或引擎自动生成的流程图。

获得流程定义的pojo版本, 可以用来通过java解析流程,而不必通过xml。

RuntimeService

Activiti的流程运行管理类。可以从这个服务类中获取很多关于流程执行相关的信息

TaskService

Activiti的任务管理类。可以从这个类中获取任务的信息。

HistoryService

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

ManagementService

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

任务监听

任务监听器是发生对应的任务相关事件时执行自定义 java 逻辑 或表达式。 任务相当事件包括:

Create:任务创建后触发
Assignment:任务分配后触发
Delete:任务完成后触发
All:所有事件发生都触发

定义任务监听类,且类必须实现 org.activiti.engine.delegate.TaskListener 接口

public class MyTaskListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        //业务代码
    }
} 

注意:使用监听器分配方式,按照监听事件去执行监听类的 notify 方法,方法如果不能正常执行也会影响任务的执行。

流程变量

流程变量就是 activiti 在管理工作流时根据管理需要而设置的变量,在流程流转时使用。

注意:如果将 对象存储到流程变量中,必须实现序列化接口 serializable,为了防止由于新增字段无法反序列化,需要生成 serialVersionUID

作用域:

globa变量:流程变量的默认作用域是流程实例(processInstance)。当一个流程变量的作用域为流程实例时,可以称为 global 变量。global 变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。

local变量:一个任务(task)或一个执行实例(execution),Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名也可以和 global 变量名相同,没有影响。

设置流程变量:

  1. 启动流程实例时设置流程变量

在启动流程时设置流程变量,变量的作用域是整个流程实例。通过Map<key,value>设置流程变量,map中可以设置多个变量,这个key就是流程变量的名字。

 Map<String,Object> map=new HashMap<>();
        Person person = new Person();
        person.setNum(2);
        map.put("holidays",person);
        map.put("assignee0","user1");
        map.put("assignee1","user2");
        map.put("assignee2","user3");
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("test-global1",map);
  1. 任务办理时设置变量

在完成任务时设置流程变量,该流程变量只有在该任务完成后其它结点才可使用该变量,它的作用域是整个流程实例,如果设置的流程变量的key在流程实例中已存在相同的名字则后设置的变量替换前边设置的变量。

 Map<String,Object> map=new HashMap<>();
        Person person = new Person();
        person.setNum(2);
        map.put("holidays",person);
        map.put("assignee0","user1");
        map.put("assignee1","user2");
        map.put("assignee2","user3");
Task task = taskService.createTaskQuery()
                .processDefinitionKey(key)
                .taskAssignee(assingee)
                .singleResult();
        if(task != null){
            //完成任务时,设置流程变量的值
            taskService.complete(task.getId(),map);
            System.out.println("任务执行完成");
        }
  1. 通过当前流程实例设置

通过流程实例id设置全局变量,该流程实例必须未执行完成。

//    当前流程实例执行 id,通常设置为当前执行的流程实例
String executionId="2601";
 Map<String,Object> map=new HashMap<>();
        Person person = new Person();
        person.setNum(2);
        map.put("holidays",person);
        map.put("assignee0","user1");
        map.put("assignee1","user2");
        map.put("assignee2","user3");
runtimeService.setVariable(executionId, "map", map);
  1. 通过当前任务设置

任务id必须是当前待办任务id,act_ru_task中存在。如果该任务已结束,会报错

		//当前待办任务id
		String taskId="1404";
        Person person = new Person();
        person.setNum(2);
        map.put("holidays",person);
        map.put("assignee0","user1");
        map.put("assignee1","user2");
        map.put("assignee2","user3");
taskService.setVariable(taskId, "map", map);

组任务

组任务办理流程

(1)查询组任务

指定候选人,查询该候选人当前的待办任务。

候选人不能立即办理任务。

//查询组任务
      List<Task> list = taskService.createTaskQuery()
             .processDefinitionKey(processDefinitionKey)
             .taskCandidateUser(userId)//根据候选人查询
             .list();

(2)拾取(claim)任务 :

该组任务的所有候选人都能拾取。将候选人的组任务,变成个人任务。原来候选人就变成了该任务的负责人。

//拾取任务
          taskService.claim(taskId, userId);

如果拾取后不想办理该任务,需要将已经拾取的个人任务归还到组里边,将个人任务变成了组任务。

注意:即使该用户不是候选人也能拾取,建议拾取时校验是否有资格,组任务拾取后,该任务已有负责人,通过候选人将查询不到该任务

归还组任务:

       // 如果设置为null,归还组任务,该 任务没有负责人
       taskService.setAssignee(taskId, null);

任务交接:

//    candidateuser指定交接人
taskService.setAssignee(taskId, candidateuser);

(3)查询个人任务

查询方式同个人任务部分,根据assignee查询用户负责的个人任务。

(4)办理个人任务

网关

网关用来控制流程的流向

排他网关(ExclusiveGateway)

排他网关,用来在流程中实现决策。 当流程执行到这个网关,所有分支都会判断条件是否为true,如果为true则执行该分支。

注:如果从网关出去的线所有条件都不满足则系统抛出异常。

并行网关ParallelGateway

并行网关允许将流程分成多条分支,也可以把多条分支汇聚到一起,并行网关的功能是基于进入和外出顺序流的:

lfork分支:

并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。

ljoin汇聚:

所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。

注:如果同一个并行网关有多个进入和多个外出顺序流, 它就同时具有分支和汇聚功能。 这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。

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

包含网关InclusiveGateway

包含网关可以看做是排他网关和并行网关的结合体。

和排他网关一样,可以在外出顺序流上定义条件,包含网关会解析它们。 但是主要的区别是包含网关可以选择多于一条顺序流,这和并行网关一样。

包含网关的功能是基于进入和外出顺序流的:

分支:

所有外出顺序流的条件都会被解析,结果为true的顺序流会以并行方式继续执行, 会为每个顺序流创建一个分支。

汇聚:

所有并行分支到达包含网关,会进入等待状态, 直到每个包含流程token的进入顺序流的分支都到达。 这是与并行网关的最大不同。换句话说,包含网关只会等待被选中执行了的进入顺序流。 在汇聚之后,流程会穿过包含网关继续执行。

事件网关EventGateway

事件网关允许根据事件判断流向。网关的每个外出顺序流都要连接到一个中间捕获事件。 当流程到达一个基于事件网关,网关会进入等待状态:会暂停执行。与此同时,会为每个外出顺序流创建相对的事件订阅。

事件网关的外出顺序流和普通顺序流不同,这些顺序流不会真的"执行", 相反它们让流程引擎去决定执行到事件网关的流程需要订阅哪些事件。 要考虑以下条件:

  1. 事件网关必须有两条或以上外出顺序流;
  2. 事件网关后,只能使用intermediateCatchEvent类型(activiti不支持基于事件网关后连接ReceiveTask)
  3. 连接到事件网关的中间捕获事件必须只有一个入口顺序流。

部分接口示例代码

    /**
     * 部署流程
     */
    @Test
    public void testDeployment() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        RepositoryService repositoryService = processEngine.getRepositoryService();
        //部署
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("holiday.bpmn20.xml")
                .name("engine1")
                .deploy();
        System.out.println("流程部署id:" + deploy.getId());
        System.out.println("流程部署名称:" + deploy.getName());

    }
     /**
     * 启动流程实例
     */
    @Test
    public void testStartProcess() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("engine1");
        System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例id:" + processInstance.getId());
        System.out.println("当前活动Id:" + processInstance.getActivityId());
        System.out.println("当前活动Id:" + processInstance.getProcessDefinitionKey());

    }
    /**
     * 查询待办任务
     */
    @Test
    public void testFindPersonalTaskList() {


        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        TaskService taskService = processEngine.getTaskService();
        List<Task> engine1 = taskService.createTaskQuery()
                .processDefinitionKey("engine1")
                .taskAssignee("user2")
                .list();
        for (Task task : engine1) {
            System.out.println("分配给我的流程定义的ID = " + task.getProcessDefinitionId());
            System.out.println("待办环节ID = " + task.getId());
            System.out.println("环节指派人员 = " + task.getAssignee());
            System.out.println("待办环节名 = " + task.getName());
        }
    }
    /**
     * 完成指定任务
     */
    @Test
    public void completTask() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        List<Task> engine1 = taskService.createTaskQuery()
                .processDefinitionKey("engine1")
                .taskAssignee("user1")
                .list();

        //完成指定待办任务
        taskService.complete(engine1.get(0).getId());
    }
    /**
     * 查询流程定义信息
     */
    @Test
    public void queryProcessDefinition() {
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("engine1")
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
        for (ProcessDefinition processDefinition : definitionList) {
            System.out.println("id=" + processDefinition.getId());
            System.out.println("name=" + processDefinition.getName());
            System.out.println("key=" + processDefinition.getKey());
            System.out.println("Version=" + processDefinition.getVersion());
            System.out.println("DeploymentId =" + processDefinition.getDeploymentId());
        }

    }
    /**
     * 流程资源下载
     */
    public void downloadFile() {

        ProcessEngineConfiguration configuration
                = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cgf.xml", "processEngineConfiguration");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        ProcessDefinition processDefinition = processDefinitionQuery.processDefinitionKey("engine1").singleResult();
        try (
                InputStream xmlStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
                InputStream pngStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName());
                FileOutputStream xmlOutputStream = new FileOutputStream(new File("D:/bpmn.xml"));
                FileOutputStream pngOutputStream = new FileOutputStream(new File("D:/bpmn.png"));
        ) {
            IOUtils.copy(xmlStream, xmlOutputStream);
            IOUtils.copy(pngStream, pngOutputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 流程历史信息查询
     */
    @Test
    public void findHistoryInfo(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        HistoryService historyService = processEngine.getHistoryService();
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
        historicActivityInstanceQuery.processInstanceId("");
        //开始时间排序
        historicActivityInstanceQuery.orderByHistoricActivityInstanceStartTime().asc();
        List<HistoricActivityInstance> activityInstances = historicActivityInstanceQuery.list();
        for (HistoricActivityInstance hi : activityInstances) {
            System.out.println(hi.getActivityId());
            System.out.println(hi.getActivityName());
            System.out.println(hi.getProcessDefinitionId());
            System.out.println(hi.getProcessInstanceId());

        }
    }
    /**
     * 全部流程挂起或激活
     */
    @Test
    public void SuspendAllProcessInstance(){
        ProcessEngineConfiguration configuration
                = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cgf.xml", "processEngineConfiguration");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        ProcessDefinition processDefinition = processDefinitionQuery.processDefinitionKey("engine1").singleResult();

        //判断目前流程处于挂起还是激活状态
        boolean suspended = processDefinition.isSuspended();//是否挂起的
        if (suspended) {
            //激活
            repositoryService.activateProcessDefinitionById(processDefinition.getId(),true,new Date());

        }else {
            //挂起
            repositoryService.suspendProcessDefinitionById(processDefinition.getId(),true,new Date());
        }
    }

    /**
     * 单个流程实例挂起或激活
     */
    @Test
    public void SuspendSingleProcessInstance(){
        ProcessEngineConfiguration configuration
                = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cgf.xml", "processEngineConfiguration");
        ProcessEngine processEngine = configuration.buildProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId("").singleResult();
        //得到当前流程所有实例是否都为暂停状态
        boolean suspended = processInstance.isSuspended();
        if (suspended) {
            runtimeService.activateProcessInstanceById(processInstance.getId());
        }else {
            runtimeService.suspendProcessInstanceById(processInstance.getId());
        }
        //某个流程实例挂起则此流程不再继续执行,完成该流程实例的当前任务将报异常。
    }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LeBron永鑫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值