activiti使用详解

1 篇文章 0 订阅
1 篇文章 0 订阅

文章目录

activiti使用详解

快速开始

在项目中添加如下依赖项

<dependency>
  <groupId>org.activiti</groupId>
  <artifactId>activiti-spring-boot-starter-basic</artifactId>
  <version>6.0.0</version>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>
  • 注意:如果项目中使用的mybatis并且使用的tk-mybatis需要做如下修改
<dependency>
  <groupId>tk.mybatis</groupId>
  <artifactId>mapper-spring-boot-starter</artifactId>
  <version>2.0.4</version>
  <exclusions>
    <exclusion>
      <artifactId>persistence-api</artifactId>
       <groupId>javax.persistence</groupId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
  • 查看一下JpaProcessEngineAutoConfiguration类,部分代码如下:
public class JpaProcessEngineAutoConfiguration {
    public JpaProcessEngineAutoConfiguration() {
    }
 
    @Configuration
    @ConditionalOnClass(
        name = {"javax.persistence.EntityManagerFactory"}
    )
    @EnableConfigurationProperties({ActivitiProperties.class})
    public static class JpaConfiguration extends AbstractProcessEngineAutoConfiguration {
        public JpaConfiguration() {
        }
    }
}
  • 可以看到EntityManagerFactory是被@ConditionlOnClass所注解的。而EntityManagerFactory是来自于JPA相关的接口。其实这里是Activiti所做的判断,如果项目使用了JPA,那走JPA,如果没有,则走Mybatis。所以只引入Mybatis和Activiti的话项目不会报错,那为什么引入了Mapper就会报错呢?继续看mapper的源码就能知道原因,其实mapper并没有实现EntityManagerFactory接口,而是自己写了一套,而在Activiti中则认为当前项目使用的是JPA,找不到EntityManagerFactory的实现类。所以报错。解决方法就是在mapper中移除对persistence-api依赖,在activiti中加上jpa的依赖。这样的话,项目启动不会报错,并且能正常使用tkmybatis,省去了公共的增删改查代码。

修改application.yml配置文件和启动类

spring:
  activiti:
    database-schema-update: true #自动检查表,没有创建表,第一次项目启动成功后可以改为false,避免重复检查
    history-level: full
    check-process-definitions: true # 自动检查,部署流程定义文件
    process-definition-location-prefix: classpath:/processes/ # 流程文件存放的目录

排除org.activiti.spring.boot.SecurityAutoConfiguration.class

package com.zzvcom.task.center;

import org.activiti.spring.boot.SecurityAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(exclude = {
        SecurityAutoConfiguration.class})
//@SpringBootApplication
public class CenterApplication {

    public static void main(String[] args) {
        SpringApplication.run(CenterApplication.class, args);
    }

}


在resources目录下新建processes目录并添加如下流程文件task_process.bpmn

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 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" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1572328617189" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="task_process_001" isClosed="false" isExecutable="true" name="试题审核流程" processType="None">
    <startEvent id="_2" name="StartEvent"/>
    <userTask activiti:exclusive="true" id="_3" name="试卷导入"/>
    <sequenceFlow id="_4" sourceRef="_2" targetRef="_3"/>
    <userTask activiti:exclusive="true" id="_5" name="试题审核"/>
    <exclusiveGateway gatewayDirection="Unspecified" id="_7" name="试题维度审核网关"/>
    <sequenceFlow id="_8" sourceRef="_5" targetRef="_7"/>
    <userTask activiti:exclusive="true" id="_9" name="试题终审"/>
    <endEvent id="_13" name="EndEvent"/>
    <sequenceFlow id="_14" sourceRef="_9" targetRef="_13"/>
    <sequenceFlow id="_10" name="审核通过" sourceRef="_7" targetRef="_9">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${adopt==true}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_11" name="驳回" sourceRef="_7" targetRef="_3">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${adopt==false}]]></conditionExpression>
    </sequenceFlow>
    <serviceTask activiti:class="com.zzvcom.task.center.task.ServiceTask" activiti:exclusive="true" id="_15" name="试题重复检查"/>
    <sequenceFlow id="_16" sourceRef="_3" targetRef="_15"/>
    <userTask activiti:exclusive="true" id="_6" name="试题重复仲裁"/>
    <exclusiveGateway gatewayDirection="Unspecified" id="_12" name="试题重复检查网关"/>
    <sequenceFlow id="_17" sourceRef="_15" targetRef="_12"/>
    <sequenceFlow id="_19" sourceRef="_12" targetRef="_5">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${repeat==false}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_20" sourceRef="_12" targetRef="_6">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${repeat==true}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="_21" sourceRef="_6" targetRef="_5"/>
  </process>
  <bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
    <bpmndi:BPMNPlane bpmnElement="task_process_001">
      <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
        <omgdc:Bounds height="32.0" width="32.0" x="55.0" y="-5.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
        <omgdc:Bounds height="55.0" width="85.0" x="30.0" y="85.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
        <omgdc:Bounds height="55.0" width="85.0" x="40.0" y="465.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_7" id="Shape-_7" isMarkerVisible="false">
        <omgdc:Bounds height="32.0" width="32.0" x="260.0" y="470.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_9" id="Shape-_9">
        <omgdc:Bounds height="55.0" width="85.0" x="35.0" y="565.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_13" id="Shape-_13">
        <omgdc:Bounds height="32.0" width="32.0" x="55.0" y="680.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_15" id="Shape-_15">
        <omgdc:Bounds height="55.0" width="85.0" x="35.0" y="185.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
        <omgdc:Bounds height="55.0" width="85.0" x="350.0" y="270.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_12" id="Shape-_12" isMarkerVisible="false">
        <omgdc:Bounds height="32.0" width="32.0" x="65.0" y="300.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_14" id="BPMNEdge__14" sourceElement="_9" targetElement="_13">
        <omgdi:waypoint x="71.0" y="620.0"/>
        <omgdi:waypoint x="71.0" y="680.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_17" id="BPMNEdge__17" sourceElement="_15" targetElement="_12">
        <omgdi:waypoint x="81.0" y="240.0"/>
        <omgdi:waypoint x="81.0" y="300.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_16" id="BPMNEdge__16" sourceElement="_3" targetElement="_15">
        <omgdi:waypoint x="75.0" y="140.0"/>
        <omgdi:waypoint x="75.0" y="185.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_19" id="BPMNEdge__19" sourceElement="_12" targetElement="_5">
        <omgdi:waypoint x="81.0" y="332.0"/>
        <omgdi:waypoint x="81.0" y="465.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_4" id="BPMNEdge__4" sourceElement="_2" targetElement="_3">
        <omgdi:waypoint x="71.0" y="27.0"/>
        <omgdi:waypoint x="71.0" y="85.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_5" targetElement="_7">
        <omgdi:waypoint x="125.0" y="492.5"/>
        <omgdi:waypoint x="260.0" y="486.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_20" id="BPMNEdge__20" sourceElement="_12" targetElement="_6">
        <omgdi:waypoint x="97.0" y="316.0"/>
        <omgdi:waypoint x="350.0" y="297.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="_7" targetElement="_3">
        <omgdi:waypoint x="275.0" y="471.0"/>
        <omgdi:waypoint x="275.0" y="220.0"/>
        <omgdi:waypoint x="115.0" y="112.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_7" targetElement="_9">
        <omgdi:waypoint x="275.0" y="501.0"/>
        <omgdi:waypoint x="275.0" y="545.0"/>
        <omgdi:waypoint x="120.0" y="592.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_21" id="BPMNEdge__21" sourceElement="_6" targetElement="_5">
        <omgdi:waypoint x="350.0" y="275.0"/>
        <omgdi:waypoint x="0.0" y="275.0"/>
        <omgdi:waypoint x="40.0" y="492.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

新建如下类

package com.zzvcom.task.center.task;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.JavaDelegate;

/**
 * 试题重复检查task
 */
public class ServiceTask implements JavaDelegate {
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("serviceTask已执行");
        execution.setVariable("repeat",false);
    }
}
package com.zzvcom.task.center.service;

import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;


@Service
public class TaskProcessService {
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private IdentityService identityService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;


    private static final String PROCESS_DEFINE_KEY = "task_process_001";

    public void startTask(String id) {
        // 查询当前任务
        Task currentTask = query(id);
        // 申明任务
//        taskService.claim(currentTask.getId(), "word1");
        taskService.complete(currentTask.getId());
    }

    public void execTask(String processId){
        execTask(processId,null);
    }
    public void execTask(String id,Map<String, Object> variables) {
        // 查询当前任务
        Task currentTask = query(id);
        taskService.complete(currentTask.getId(),variables);
    }

    public String createTask() {
        // 开始流程
        ProcessInstance vacationInstance = runtimeService.startProcessInstanceByKey(PROCESS_DEFINE_KEY);
        return vacationInstance.getId();
    }

    public Task query(String id) {

        // 查询当前任务
        Task currentTask = taskService.createTaskQuery().processInstanceId(id).singleResult();
        return currentTask;
    }

    public Task query(String id,String name){
        // 查询当前任务
        Task currentTask = taskService.createTaskQuery().processInstanceId(id).taskName(name).singleResult();
        return currentTask;
    }
}

编写测试类

package com.zzvcom.task.center;

import com.zzvcom.task.center.service.TaskProcessService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.task.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TaskProcessTest extends CenterApplicationTests {
    @Autowired
    private TaskProcessService taskProcessService;

    @Resource
    private HistoryService historyService;

    /**
     * 测试试题重复进入试题重复仲裁,并在审核task时有驳回
     */
    @Test
    public void test001(){
        System.out.println("创建一个流程");
        String processId = taskProcessService.createTask();
        System.out.println("流程id:"+processId);
        System.out.println("试题导入task");
        taskName(processId);
        Map<String,Object> variables = new HashMap<>();
        System.out.println("提交流程试题导入task并进行试题重复检查");
        variables.put("firstSubmit",true); // 第一次提交进行试题重复检查
        variables.put("repeatFlag",true); // 此处进行模拟让试题重复,进入试题重复仲裁task
        taskProcessService.execTask(processId,variables);
        taskName(processId);
        System.out.println("提交试题重复仲裁task");
        taskProcessService.execTask(processId);
        taskName(processId);
        System.out.println("提交试题审核task-审核不通过进行驳回");
        variables.put("adopt",false);
        taskProcessService.execTask(processId,variables);
        taskName(processId);
        System.out.println("驳回后再次提交试题导入task,不进行试题重复检查");
        variables.put("firstSubmit",false); // 应为是驳回提交,所以不需要再次进行试题重复检查
        taskProcessService.execTask(processId,variables);
        taskName(processId);
        System.out.println("提交试题审核task,审核通过");
        variables.put("adopt",true);
        taskProcessService.execTask(processId,variables);
        taskName(processId);
        System.out.println("提交试题终审task");
        taskProcessService.execTask(processId);
        System.out.println("任务结束-输出流程记录--------------------------");
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().processInstanceId(processId);
        List<HistoricTaskInstance> list = historicTaskInstanceQuery.finished().list();
        for (HistoricTaskInstance hti : list) {
            System.out.println(hti.getId()+"==="+hti.getName());
        }
    }

    /**
     * 测试试题不重复,并在审核时有驳回
     */
    @Test
    public void test002(){
        System.out.println("创建一个流程");
        String processId = taskProcessService.createTask();
        System.out.println("流程id:"+processId);
        System.out.println("试题导入task");
        taskName(processId);
        Map<String,Object> variables = new HashMap<>();
        System.out.println("提交流程试题导入task并进行试题重复检查");
        variables.put("firstSubmit",true); // 第一次提交进行试题重复检查
//        variables.put("repeatFlag",true); // 此处进行模拟让试题重复,进入试题重复仲裁task
        taskProcessService.execTask(processId,variables);
        taskName(processId);
//        System.out.println("提交试题重复仲裁task");
//        taskProcessService.execTask(processId);
//        taskName(processId);
        System.out.println("提交试题审核task-审核不通过进行驳回");
        variables.put("adopt",false);
        taskProcessService.execTask(processId,variables);
        taskName(processId);
        System.out.println("驳回后再次提交试题导入task,不进行试题重复检查");
        variables.put("firstSubmit",false); // 应为是驳回提交,所以不需要再次进行试题重复检查
        taskProcessService.execTask(processId,variables);
        taskName(processId);
        System.out.println("提交试题审核task,审核通过");
        variables.put("adopt",true);
        taskProcessService.execTask(processId,variables);
        taskName(processId);
        System.out.println("提交试题终审task");
        taskProcessService.execTask(processId);
        System.out.println("任务结束-输出流程记录--------------------------");
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().processInstanceId(processId);
        List<HistoricTaskInstance> list = historicTaskInstanceQuery.finished().list();
        for (HistoricTaskInstance hti : list) {
            System.out.println(hti.getId()+"==="+hti.getName());
        }
    }

    /**
     * 测试试题重复,试题审核时没有驳回
     */
    @Test
    public void test003(){
        System.out.println("创建一个流程");
        String processId = taskProcessService.createTask();
        System.out.println("流程id:"+processId);
        System.out.println("试题导入task");
        taskName(processId);
        Map<String,Object> variables = new HashMap<>();
        System.out.println("提交流程试题导入task并进行试题重复检查");
        variables.put("firstSubmit",true); // 第一次提交进行试题重复检查
        variables.put("repeatFlag",true); // 此处进行模拟让试题重复,进入试题重复仲裁task
        taskProcessService.execTask(processId,variables);
        taskName(processId);
        System.out.println("提交试题重复仲裁task");
        taskProcessService.execTask(processId);
        taskName(processId);
        System.out.println("提交试题审核task,审核通过");
        variables.put("adopt",true);
        taskProcessService.execTask(processId,variables);
        taskName(processId);
        System.out.println("提交试题终审task");
        taskProcessService.execTask(processId);
        System.out.println("任务结束-输出流程记录--------------------------");
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery().processInstanceId(processId);
        List<HistoricTaskInstance> list = historicTaskInstanceQuery.finished().list();
        for (HistoricTaskInstance hti : list) {
            System.out.println(hti.getId()+"==="+hti.getName());
        }
    }

    public void taskName(String taskId){
        Task query = taskProcessService.query(taskId);
        System.out.println("task名称:"+query.getName());
    }
}

activiti核心api

流程引擎及服务

  • RepositoryService 流程仓库Service,可以管理流程仓库例如部署删除读取流程资源
  • RuntimeService 运行时Service可以处理所有运行状态的流程实例流程控制(开始,暂停,挂起等)
  • TaskService 任务Service用于管理、查询任务,例如签收、办理、指派等
  • IdentitiServicec 身份Service可以管理查询用户、组之间的关系
  • FormService 表单Service用于读取和流程、任务相关的表单数据
  • HistoryService 历史Service用于查询所有的历史数据
  • ManagementService 引擎管理Service,和具体业务无关,主要查询引擎配置,数据库作业
  • DynamicBpmService 动态bpm服务

流程存储服务 RepositoryService

  • 管理流程定义文件xml及静态资源服务
  • 对流程定义文件对暂停激活
  • 流程定义启动权限管理
  • 部署文件构造器DeploymentBuilder
  • 部署文件查询器DeploymentQuery
  • 流程定义文件查询对象ProcessDefinitionQuery
api
方法描述库表字段
repositoryService.createDeployment().addClasspathResource(“参数”) .deploy()部署流程 resources文件下面的xml流程文件省略
repositoryService.createDeploymentQuery().list()查询所有部署省略
repositoryService.createProcessDefinitionQuery().list()查询所有部署的流程省略
repositoryService.suspendProcessDefinitionById(id)或ByKey根据流程id挂起流程修改表ACT_RE_PROCDEF字段SUSPENSION_STATE_:1激活 2挂起
repositoryService.activateProcessDefinitionById(id)或ByKey根据流程id激活流程修改表ACT_RE_PROCDEF字段SUSPENSION_STATE_:1激活 2挂起
repositoryService.addCandidateStarterUser(流程id,用户id)添加流程与用户关系操作ACT_RU_IDENTITYLINK表
repositoryService.deleteCandidateStarterGroup(流程id,用户组id)添加流程与用户组关系操作ACT_RU_IDENTITYLINK表
repositoryService.deleteCandidateStarterUser(流程id,用户id)删除流程与用户关系操作ACT_RU_IDENTITYLINK表
repositoryService.deleteCandidateStarterGroup(流程id,用户组id)删除流程与用户组关系操作ACT_RU_IDENTITYLINK表
repositoryService.getIdentityLinksForProcessDefinition(流程id)查询流程对应用户跟组关系查询ACT_RU_IDENTITYLINK表

流程运行控制服务 RuntimeService

  • 启动流程及对流程数据对控制
  • 流程实例(ProcessInstance)与执行流(Execution)查询
  • 触发流程操作、接收消息和信号
启动流程变量管理
  • 启动流程的常用方式(id,key,message)
  • 启动流程可选参数(businesskey,variables,tenantId)
  • 变量(variables)的设置和获取
流程实例与执行流
  • 流程实例(ProcessInstance)表示一次工作流业务的数据实体
  • 执行流(Execution)表示流程实例中具体的执行路径
  • 流程实例接口继承与执行流
流程触发
  • 使用trigger触发ReceiveTask节点
  • 触发信号捕获事件signalEvenReceived
  • 触发消息捕获事件messageEventReceived
api
方法描述
runtimeService.startProcessInstanceByKey(String processDefinitionKey, Map<String, Object> variables)根据部署流程key启动一个流程
runtimeService.startProcessInstanceById(String processDefinitionId, Map<String, Object> variables)根据部署流程id启动一个流程
runtimeService.createProcessInstanceBuilder().businessKey(“businessKey001”) .processDefinitionKey(String processDefinitionKey).variables( Map<String, Object> variables) .start()根据processInstanceBuilder启动流程
runtimeService.getVariables(processInstance.getId())根据流程实例id获取传参
runtimeService.setVariable(processInstance.getId(),“key3”,“value3”)新增或修改参数
runtimeService.createProcessInstanceQuery().processInstanceId(processInstance.getId())查询流程实例
runtimeService.createExecutionQuery()获取流程执行对象

任务管理服务 TaskService

  • 对用户任务(UserTask)管理和流程控制
  • 设置用户任务(UserTask)对权限信息(拥有者,候选人,办理人)
  • 针对用户任务添加任务附件、任务;评价和事件记录
TaskService对Task管理与流程控制
  • Task对象对创建,删除
  • 查询Task,并驱动Task节点完成执行
  • Task相关参数变量(variable)设置
方法描述
taskService.createTaskQuery().list()查询所有任务
taskService.setVariable(“任务id”,“键”,“值”)设置普通变量
taskService.setVariableLocal(“任务id”,“键”,“值”)设置本地变量
taskService.getVariables(“任务id”)获取普通变量
taskService.getVariablesLocal((“任务id”)获取本地变量
runtimeService.getVariables(task.getExecutionId())通过流获取变量
taskService.complete(“任务id”,“传值Map”)到下一个节点
TaskService设置Task权限信息
  • 候选用户(candidateUser)和候选组(candidateGroup)
  • 指定拥有人(Owner)和办理人(Assignee)
  • 通过claim设置办理人
方法描述
taskService.setOwner(“taskId”,“user”)设置流程发起人
taskService.claim("“taskId”",“user”)指定代办人
taskService.addCandidateUser(“user”)添加候选人
taskService.addCandidateGroup(“group”)添加候选组
taskService.createTaskQuery().taskCandidateUser(“user”).taskUnassigned().list()查询候选人列表有user但是没指定代办人任务
taskService.createTaskQuery().taskCandidateUser(“user”).taskUnassigned().list()查询候选人列表有我但是没指定代办人任务
taskService.createTaskQuery().taskAssignee(“user”).list()查询代办人为user的任务
taskService.getIdentityLinksForTask(“taskId”)查询任务与人员之间的关系
TaskService设置Task附加信息
  • 任务附件(Attachment)创建与查询
  • 任务评价(Comment)创建与查询
方法描述
taskService.createAttachment(“类型”,“任务id”,“流程Id”,“附件名称”,“附件描述”,"流或者url)上传附件
taskService.getTaskAttachments(“任务id”)获取附件
taskService.addComment(“任务id”,“流程id”,“批注1”)添加审批批注
taskService.getTaskComments(“任务id”)查询审批批注
taskService.getTaskEvents(“任务id”)查询任务日志记录

身份管理服务 IdentityService

  • 管理用户(User)
  • 管理用户组(Group)
  • 用户与用户组关系(Membership)
方法描述
dentityService.newUser(“userid”)创建一个用户
identityService.newGroup(“groupid”)创建一个组
identityService.saveUser(user)保存或者更新用户
identityService.saveGroup(group)保存或者更新组
identityService.createUserQuery()查询用户
identityService.createGroupQuery()查询组

表单服务管理 FormService

  • 解析流程定义中表单项的配置
  • 提交表单的方式驱动用户节点流转
  • 获取自定义外部表单key
方法描述
formService.getStartFormKey(processDefinition.getId())部署流程的id获取表单key
formService.getStartFormData(processDefinition.getId()).getFormProperties()获取开始节点表单内容
formService.getStartFormData(processDefinition.getId()).getFormProperties()获取开始节点表单内容
formService.submitStartFormData(processDefinition.getId(), “传值参数”)通过formservice启动流程
formService.submitTaskFormData(“taskId”,“传参数”)formService.submitTaskFormData(“taskId”,“传参数”)
formService.getTaskFormData(“taskId”)通过taskid获取task节点表单内容

历史管理服务 HistoryService

  • 管理流程实例结束后的历史数据
  • 构建历史数据查询对象
  • 根据流程实例id删除流程历史数据
历史数据实体描述
Historicprocessinstance历史流程实例实体类
Historicvariablelnstance流程或任务变量值的实体类
Historicactivityinstance单个活动节点执行的信息
Historictaskinstance用户任务实例的的信息
Historicdetail历史流程活动任务详细信息
HistoryService构建历史查询对象
  • create[历史数据实体]Query
  • createNative[历史数据实体]Query | 通过原生sql查询
  • createProcessInstanceHistoryLogQuery | 查询一个流程实例的所有其他数据
HistoryService删除历史操作
  • deleteHistoricProcessInstance | 删除历史流程实例及联删除其他信息
  • deleteHistoricTaskInstance | 删除历史的task实例
方法描述
historyService.createHistoricProcessInstanceQuery()查询流程实例变量
historyService.createHistoricActivityInstanceQuery()查询活动节点
historyService.createHistoricTaskInstanceQuery()查询任务实例
historyService.createHistoricVariableInstanceQuery()查询流程任务变量
historyService.createHistoricDetailQuery()历史任务流程活动详细信息
historyService.createProcessInstanceHistoryLogQuery(“流程实例id”)查询一个流程实例的所有其他数据
historyService.deleteHistoricProcessInstance(“流程实例id”)删除历史流程实例
historyService.deleteHistoricTaskInstance(“taskid”)删除历史任务

其他管理服务

  • 管理服务ManagementService
  • 动态流程定义服务DynamicBpmnService
ManagementService
  • job任务管理
  • 数据库相关通用操作
  • 执行流程引擎命令(Command)
Job任务查询
  • JobQuery 查询一般工作
  • TimerJobQuery 查询定时工作
  • SuspendedJobQuery 查询中断工作
  • DeadLetterJobQuery 查询无法执行的工作
方法描述
managementService.createTimerJobQuery()查询定时工作
managementService.createJobQuery()查询一般工作
managementService.createSuspendedJobQuery()查询中断工作
managementService.createDeadLetterJobQuery()查询无法执行的工作
数据库相关操作
  • 查询表结构元数据(TableMetaData)
  • 通用查询(TablePageQuery)
  • 执行自定义Sql查询(executeCustomSql)
方法描述
managementService.createTablePageQuery().tableName(managementService.getTableName(class))查询实体到所有数据
managementService.executeCustomSql()自定义sql查

异常策略 ActivitiEXception

  • ActivitiWrongDbException 引擎与数据库版本不匹配
  • ActivitiOptimisticLockingException 并发导致乐观锁异常
  • ActivitiClassLoadingException 加载类异常
  • ActivitiObjectNotFoundException 操作对象不存在
  • ActivitilllegalArgumentException 非法的参数
  • ActivitiTaskAlreadyClaimedException 任务被重新声明代理人
  • BpmnError 定义业务异常控制流程

bpmn文件详解

bpmn各节点详解

  • bpmn文件是activiti配置流程定义的文件,一般一个bpmn文件定义一个流程,文件为xml格式,各种元素级别如下:
<?xml version="1.0" encoding="UTF-8"?>
<definitions>
  <process>
    <startEvent></startEvent>
    <endEvent></endEvent>
    <userTask>
        <extensionElements>
      <activiti:taskListener></activiti:taskListener>
    </extensionElements>
    </userTask>
    <scriptTask/>
    <manualTask/>
    <receiveTask/>
    <serviceTask/>
    <businessRuleTask/>
    <exclusiveGateway/>
    <parallelGateway/>
    <sequenceFlow>
        <conditionExpression></conditionExpression>
    </sequenceFlow>
    <subProcess></subProcess>
    <boundaryEvent/></boundaryEvent>
  </process>
  <bpmndi:BPMNDiagram>
    <bpmndi:BPMNPlane>
      <bpmndi:BPMNShape>
        <omgdc:Bounds></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape>
        <omgdc:Bounds></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape>
        <omgdc:Bounds></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape>
        <omgdc:Bounds></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge>
        <omgdi:waypoint></omgdi:waypoint>
        <omgdi:waypoint></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
  • process: 流程定义根元素,代表了一个流程定义的开始,属性如下
属性名含义
id流程唯一id,启动流程时需要
isExecutable流程是否可执行
name流程名称
type流程类型
isClosed流程是否已关闭,关闭不能执行
  • startEvent: 流程启动事件,一个process只能有一个,且必须为流程起始元素
属性名含义
id启动节点id
name启动节点名称
  • endEvent: 流程结束事件,一个process只能有一个,且必须为流程结束元素
属性名含义
id结束节点id
name节点名称
  • userTask: 流程中间用户任务,夹在startEvent与endEvent之间的节点
属性名含义
id任务id,使用id操作任务
name任务名称
activiti:assignee任务所属用户,只能指定用户完成这个任务,即任务办理人
activiti:candidateUsers多个任务办理人
activiti:candidateGroups任务处理人候选组,处理人必须在这个组内
activiti:exclusive独家的,好像是在排它性网关中使用,意思应该是在有并行分支情况下,只会走其中一条
activiti:dueDate设置用户任务到期日期
activiti:priority用户任务优先级,0-100
  • extensionElements: userTask的子元素,用于扩展元素
  • activiti:taskListener: 扩展元素之一,用于监听某个任务的运行
属性名含义
event监听的任务事件名,create、assignment(分配任务)、complete
class任务监听器类,需要实现TaskListener
  • event (required): 事件类型.。支持的类型有:
    • create: 任务被创建,并且所有的属性都被设置好后。
    • assignment: 任务被委派给某人后.。注意: 当流程执行到达一个userTask时,会先触发一个assignment事件,再触发create事件。
    • complete:在任务完成后,且被从运行时数据(runtime data)中删除前触发。
    • delete: 在任务将要被删除之前发生。注意,当任务通过completeTask完成任务时,它也会被执行。
<userTask id="myTask" name="My Task" >
  <extensionElements>
    <activiti:taskListener event="create" class="org.activiti.MyTaskCreateListener" />
  </extensionElements>
</userTask>
public class MyTaskCreateListener implements TaskListener {

  public void notify(DelegateTask delegateTask) {
    // Custom logic goes here
  }
}
  • sequenceFlow: 顺序流分为两种:标准顺序流 条件顺序流,其实就是连接两个节点的一条线
属性名含义
id顺序流id
sourceRef连线的起始节点id,即接近startEvent的节点
targetRef连线结束节点id,即接近endEvent的节点
  • conditionExpression: sequenceFlow子元素,根据表达式确定是否执行这一顺序流,一条顺序流只能联系两个节点。如果需要表达式判断,有多条顺序流连接了同一开始节点,一般这样的开始节点都是网关
    |属性名|含义|
    |—|---|
    |xsi:type|含义不知道,值为tFormalExpression|
    |子元素|表达式,${days <= 3}|

  • exclusiveGateway: 排它性网关,即多个sequenceFlow以网关节点开始时,只根据条件执行其中一条流,其他流不再判断。虽然与userTask同属于节点,但是其不作为任务执行。

属性名含义
id节点id
name节点名称
gatewayDirection网关方向,Unspecified
  • receiveTask: 接收任务(ReceiveTask)即等待任务,接收任务是一个简单任务,它会等待对应消息的到达。当前,官方只实现了这个任务的java语义。 当流程达到接收任务,流程状态会保存到数据库中。在任务创建后,意味着流程会进入等待状态,直到引擎接收了一个特定的消息, 这会触发流程穿过接收任务继续执行。
  • manualTask: 手工任务就是一个自动执行的过程。手动任务几乎不在程序中做什么事情,只是在流程的历史中留下一点痕迹,表明流程是走过某些节点的。而且这个任务是无法用taskservice查询到的。
  • mailTask: 邮件task,用于发送邮件
    • 添加依赖
<dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-email</artifactId>
 <version>1.5</version>
</dependency>
<dependency>
 <groupId>commons-logging</groupId>
 <artifactId>commons-logging</artifactId>
 <version>1.2</version>
</dependency>
- 修改application.yml,这里以网易企业邮箱为例
spring:
 activiti:
   mail-server-host: smtphz.qiye.163.com # 服务器地址
   mail-server-port: 994 # 端口
   mail-server-user-name: ***@zzvcom.com # 用户名
   mail-server-password:  # 密码或者授权码
   mail-server-use-ssl: true
  • 编写bpmn文件
<serviceTask id="sid-A360E361-0D09-460E-9F4D-3A97DD7E3D51" name="发送邮件" activiti:type="mail">
      <extensionElements>
      <!-- 收件人地址 -->
        <activiti:field name="to">
          <activiti:string><![CDATA[***@zzvcom.com]]></activiti:string>
        </activiti:field>
        <!-- 发件人地址 -->
        <activiti:field name="from">
          <activiti:string><![CDATA[***@zzvcom.com]]></activiti:string>
        </activiti:field>
        <!-- 邮件主题 -->
        <activiti:field name="subject">
          <activiti:string><![CDATA[Activity测试邮件]]></activiti:string>
        </activiti:field>
        <activiti:field name="text">
          <activiti:string><![CDATA[这是测试邮件]]></activiti:string>
        </activiti:field>
        <!-- 邮件内容 -->
        <activiti:field name="html">
          <activiti:string><![CDATA[测试]]></activiti:string>
        </activiti:field>
        <activiti:field name="charset">
          <activiti:string><![CDATA[UTF-8]]></activiti:string>
        </activiti:field>
      </extensionElements>
</serviceTask>
PropertyRequired?Description
mailServerHostnoThe hostname of your mail server (e.g. mail.mycorp.com). Default is localhost
mailServerPortyes, if not on the default portThe port for SMTP traffic on the mail server. The default is 25
mailServerDefaultFromnoThe default e-mail address of the sender of e-mails, when none is provided by the user. By default this is activiti@activiti.org
mailServerUsernameif applicable for your serverSome mail servers require credentials for sending e-mail. By default not set.
mailServerPasswordif applicable for your serverSome mail servers require credentials for sending e-mail. By default not set.
mailServerUseSSLif applicable for your serverSome mail servers require ssl communication. By default set to false.
mailServerUseTLSif applicable for your serverSome mail servers (for instance gmail) require TLS communication. By default set to false.
  • The Email task is configured by field injection. All the values for these properties can contain EL expression, which are resolved at runtime during process execution. Following properties can be set:
PropertyRequired?Description
toyesThe recipients if the e-mail. Multiple recipients are defined in a comma-separated list
fromnoThe sender e-mail address. If not provided, the default configured from address is used.
subjectnoThe subject of the e-mail.
ccnoThe cc’s of the e-mail. Multiple recipients are defined in a comma-separated list
bccnoThe bcc’s of the e-mail. Multiple recipients are defined in a comma-separated list
charsetnoAllows to change the charset of the email, which is necessary for many non-English languages.
htmlnoA piece of HTML that is the content of the e-mail.
textnoThe content of the e-mail, in case one needs to send plain none-rich e-mails. Can be used in combination with html, for e-mail clients that don’t support rich content. The client will then fall back to this text-only alternative.
htmlVarnoThe name of a process variable that holds the HTML that is the content of the e-mail. The key difference between this and html is that this content will have expressions replaced before being sent by the mail task.
textVarnoThe name of a process variable that holds the plain text content of the e-mail. The key difference between this and html is that this content will have expressions replaced before being sent by the mail task.
ignoreExceptionnoWhether an failure when handling the e-mail throws an ActivitiException. By default this is set to false.
exceptionVariableNamenoWhen email handling does not throw an exception since ignoreException = true a variable with the given name is used to hold a failure message
- The following XML snippet shows an example of using the Email Task.
<serviceTask id="sendMail" activiti:type="mail">
  <extensionElements>
    <activiti:field name="from" stringValue="order-shipping@thecompany.com" />
    <activiti:field name="to" expression="${recipient}" />
    <activiti:field name="subject" expression="Your order ${orderId} has been shipped" />
    <activiti:field name="html">
      <activiti:expression>
        <![CDATA[
           <html>
               <body>
                 Hello ${male ? 'Mr.' : 'Mrs.' } ${recipientName},<br/><br/>
                
                 As of ${now}, your order has been <b>processed and shipped</b>.<br/><br/>
                
                 Kind regards,<br/>
                
                 TheCompany.
               </body>
           </html>
      ]]>
      </activiti:expression>
    </activiti:field>
  </extensionElements>
</serviceTask>

serviceTask使用的多种方式

  • 实现JavaDelegate或ActivityBehavior
  • 执行解析代理对象的表达式
  • 调用一个方法表达式
  • 调用一直值表达式
  • 执行一个在流程执行中调用的类, 需要在’activiti:class’属性中设置全类名。
<serviceTask id="javaService"
             name="My Java Service Task"
             activiti:class="org.activiti.MyJavaDelegate" />
  • 也可以使用表达式调用一个对象。对象必须遵循一些规则, 并使用activiti:class属性进行创建。
<serviceTask id="serviceTask" activiti:delegateExpression="${delegateExpressionBean}" />
  • 这里,delegateExpressionBean是一个实现了JavaDelegate接口的bean, 它定义在实例的spring容器中。
  • 要指定执行的UEL方法表达式, 需要使用activiti:expression。
<serviceTask id="javaService"
             name="My Java Service Task"
             activiti:expression="#{printer.printMessage()}" />
  • 方法printMessage(无参数)会调用 名为printer对象的方法。
  • 也可以为表达式中的方法传递参数。
<serviceTask id="javaService"
             name="My Java Service Task"
             activiti:expression="#{printer.printMessage(execution, myVar)}" />
  • 这会调用名为printer对象上的方法printMessage。 第一个参数是DelegateExecution,在表达式环境中默认名称为execution。 第二个参数传递的是当前流程的名为myVar的变量。
  • 要指定执行的UEL值表达式, 需要使用activiti:expression属性。
<serviceTask id="javaService"
             name="My Java Service Task"
             activiti:expression="#{split.ready}" />
  • ready属性的getter方法,getReady(无参数), 会作用于名为split的bean上。 这个对象会被解析为流程对象和 (如果合适)spring环境中的对象。

  • 实现

    • 要在流程执行中实现一个调用的类,这个类需要实现org.activiti.engine.delegate.JavaDelegate接口, 并在execute方法中提供对应的业务逻辑。 当流程执行到特定阶段,它会指定方法中定义好的业务逻辑, 并按照默认BPMN 2.0中的方式离开节点。
  • 让我们创建一个java类的例子,它可以流程变量中字符串转换为大写。 这个类需要实现org.activiti.engine.delegate.JavaDelegate接口, 这要求我们实现execute(DelegateExecution)方法。 它包含的业务逻辑会被引擎调用。流程实例信息,如流程变量和其他信息, 可以通过 DelegateExecution 接口访问和操作。

public class ToUppercase implements JavaDelegate {

  public void execute(DelegateExecution execution) throws Exception {
    String var = (String) execution.getVariable("input");
    var = var.toUpperCase();
    execution.setVariable("input", var);
  }

}
  • 注意:serviceTask定义的class只会创建一个java类的实例。 所有流程实例都会共享相同的类实例,并调用execute(DelegateExecution)。 这意味着,类不能使用任何成员变量,必须是线程安全的,它必须能模拟在不同线程中执行。 这也影响着属性注入的处理方式。

  • 流程定义中引用的类(比如,使用activiti:class)不会 在部署时实例化。只有当流程第一次执行到使用类的时候, 类的实例才会被创建。如果找不到类,会抛出一个ActivitiException。 这个原因是部署环境(更确切是的classpath)和真实环境往往是不同的。 比如当使用ant或业务归档上传到Activiti Explorer来发布流程 classpath没有包含引用的类。

<activiti:string>标签和<activiti:expression>标签

activiti:resultVariable用于表示返回值

<serviceTask id="aMethodExpressionServiceTask"
    activiti:expression="#{myService.doSomething()}"
    activiti:resultVariable="myVar" />

执行监听器( Execution listener)

相关类:

  • org.activiti.engine.delegate.ExecutionListener
  • org.activiti.engine.delegate.TaskListener
  • org.activiti.engine.delegate.Expression

在流程实例执行的过程中触发某个事件时,执行监听器允许你去执行额外的java代码或者对指定的表达式求值。可以被捕捉的事件有:

  • Start and ending of a process instance.

  • Taking a transition.

  • Start and ending of an activity.

  • Start and ending of a gateway.

  • Start and ending of intermediate events.

  • Ending a start event or starting an end event.

  • 包含3个执行监听器的流程定义:

<process id="executionListenersProcess">

  <extensionElements>
    <activiti:executionListener class="org.activiti.examples.bpmn.executionlistener.ExampleExecutionListenerOne" event="start" />
  </extensionElements>

  <startEvent id="theStart" />
  <sequenceFlow sourceRef="theStart" targetRef="firstTask" />

  <userTask id="firstTask" />
  <sequenceFlow sourceRef="firstTask" targetRef="secondTask">
    <extensionElements>
      <activiti:executionListener class="org.activiti.examples.bpmn.executionListener.ExampleExecutionListenerTwo" />
    </extensionElements>
  </sequenceFlow>

  <userTask id="secondTask" >
    <extensionElements>
      <activiti:executionListener expression="${myPojo.myMethod(execution.event)}" event="end" />
    </extensionElements>
  </userTask>
  <sequenceFlow sourceRef="secondTask" targetRef="thirdTask" />

  <userTask id="thirdTask" />
  <sequenceFlow sourceRef="thirdTask" targetRef="theEnd" />

  <endEvent id="theEnd" />

</process>
  • 当进程启动时,将通知第一个执行侦听器。侦听器是一个外部java类(如ExampleExecutionListenerOne),它应该实现org.activiti.engine.delegate.ExecutionListener接口。当事件发生时(在本用例中为end事件),方法nitify会被调用。
public class ExampleExecutionListenerOne implements ExecutionListener {

  public void notify(ExecutionListenerExecution execution) throws Exception {
    execution.setVariable("variableSetInExecutionListener", "firstValue");
    execution.setVariable("eventReceived", execution.getEventName());
  }
}
  • 它也可以是一个实现了org.activiti.engine.delegate.JavaDelegate接口的委托类,这些委托类可以在其它的结构中重用,比如serviceTask的delegation。当执行过渡时( when the transition is taken)第二个侦听器会被调用。注意listener 元素没有定义event属性,因为在过渡的时候,只会触发take事件。当在过渡中(sequenceFlow 元素)定义侦听器时,event属性中的值将被忽略。当活动secondTask结束时会调用第三个执行侦听器。在侦听器的申明中没有使用class属性,而是使用expression 属性定义了一个表达式
<activiti:executionListener expression="${myPojo.myMethod(execution.eventName)}" event="end" />
  • 与其他表达式一样,执行变量execution 可以被解析使用。因为执行实现对象拥有一个暴露事件名的属性,所以可以使用execution.eventName将事件名称传递给您的方法。执行侦听器也支持delegateExpression 类似于service Task
<activiti:executionListener event="start" delegateExpression="${myExecutionListenerBean}" />
  • 执行侦听器还支持script execution listener,需要实现 org.activiti.engine.impl.bpmn.listener.ScriptExecutionListener接口
<activiti:executionListener event="start" class="org.activiti.engine.impl.bpmn.listener.ScriptExecutionListener" >
  <activiti:field name="script">
    <activiti:string>
      def bar = "BAR";  // local variable
      foo = "FOO"; // pushes variable to execution context
      execution.setVariable("var1", "test"); // test access to execution instance
      bar // implicit return value
    </activiti:string>
  </activiti:field>
  <activiti:field name="language" stringValue="groovy" />
  <activiti:field name="resultVariable" stringValue="myVar" />
</activiti:executionListener>
  • 将属性注入到执行侦听器中,当执行侦听器是通过class属性指定的,我们可以为实例化后的对象注入属性。
  • 执行侦听器属性注入的一个简单例子:
<process id="executionListenersProcess">
  <extensionElements>
    <activiti:executionListener class="org.activiti.examples.bpmn.executionListener.ExampleFieldInjectedExecutionListener" event="start">
      <activiti:field name="fixedValue" stringValue="Yes, I am " />
      <activiti:field name="dynamicValue" expression="${myVar}" />
    </activiti:executionListener>
  </extensionElements>

  <startEvent id="theStart" />
  <sequenceFlow sourceRef="theStart" targetRef="firstTask" />

  <userTask id="firstTask" />
  <sequenceFlow sourceRef="firstTask" targetRef="theEnd" />

  <endEvent id="theEnd" />
</process>
public class ExampleFieldInjectedExecutionListener implements ExecutionListener {

  private Expression fixedValue;

  private Expression dynamicValue;

  public void notify(ExecutionListenerExecution execution) throws Exception {
    execution.setVariable("var", fixedValue.getValue(execution).toString() + dynamicValue.getValue(execution).toString());
  }
}

Activiti 23张表

Activiti使用到的表都是ACT_开头的。

  • ACT_RE_*:

’RE’表示repository(存储),RepositoryService接口所操作的表。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。

  • ACT_RU_*:

‘RU’表示runtime,运行时表-RuntimeService。这是运行时的表存储着流程变量,用户任务,变量,职责(job)等运行时的数据。Activiti只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。

  • ACT_ID_*:

’ID’表示identity (组织机构),IdentityService接口所操作的表。用户记录,流程中使用到的用户和组。这些表包含标识的信息,如用户,用户组,等等。

  • ACT_HI_*:

’HI’表示history,历史数据表,HistoryService。就是这些表包含着流程执行的历史相关数据,如结束的流程实例,变量,任务,等等

  • ACT_GE_*:

全局通用数据及设置(general),各种情况都使用的数据。

23张表概述

表名说明
act_ge_bytearray二进制数据表
act_ge_property属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录,
act_hi_actinst历史节点表
act_hi_attachment历史附件表
act_hi_comment历史意见表
act_hi_identitylink历史流程人员表
act_hi_detail历史详情表,提供历史变量的查询
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_subscrthrowEvent、catchEvent时间监听信息表
act_ru_execution运行时流程执行实例表
act_ru_identitylink运行时流程人员表,主要存储任务节点与参与者的相关信息
act_ru_job运行时定时任务数据表
act_ru_task运行时任务节点表
act_ru_variable运行时流程变量数据表

23张表详解

二进制数据表(act_ge_bytearray)

保存流程定义图片和xml、Serializable(序列化)的变量,即保存所有二进制数据,特别注意类路径部署时候,不要把svn等隐藏文件或者其他与流程无关的文件也一起部署到该表中,会造成一些错误(可能导致流程定义无法删除)

字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)Y主键ID
REV_乐观锁intYVersion(版本)
NAME_名称nvarchar(255)Y部署的文件名称,如:leave.bpmn.png,leave.bpmn20.xml
DEPLOYMENT_ID_部署IDnvarchar(64)Y部署表ID
BYTES_字节varbinary(max)Y部署文件
GENERATED_是否是引擎生成tinyintY0为用户生成,1为activiti生成
属性数据表(act_ge_property)

属性数据表。存储整个流程引擎级别的数据。

字段名称字段描述数据类型主键为空取值说明
NAME_名称nvarchar(64)schema.versionschema.historynext.dbid
VALUE_nvarchar(300)5.create(5.)
REV_乐观锁intversion
历史节点表(act_hi_actinst)

历史活动信息。这里记录流程流转过的所有节点,与HI_TASKINST不同的是,taskinst只记录usertask内容

字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)
PROC_DEF_ID_流程定义IDnvarchar(64)
PROC_INST_ID_流程实例IDnvarchar(64)
EXECUTION_ID_执行实例IDnvarchar(64)
ACT_ID_节点IDnvarchar(225)节点定义ID
TASK_ID_任务实例IDnvarchar(64)任务实例ID 其他节点类型实例ID在这里为空
CALL_PROC_INST_ID_调用外部的流程实例IDnvarchar(64)调用外部流程的流程实例ID’
ACT_NAME_节点名称nvarchar(225)节点定义名称
ACT_TYPE_节点类型nvarchar(225)如startEvent、userTask
ASSIGNEE_签收人nvarchar(64)节点签收人
START_TIME_开始时间datetime2013-09-15 11:30:00
END_TIME_结束时间datetime2013-09-15 11:30:00
DURATION_耗时numeric(19,0)毫秒值
历史附件表( act_hi_attachment )
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)主键ID
REV_乐观锁integerVersion
USER_ID_用户IDnvarchar(255)用户ID
NAME_名称nvarchar(255)附件名称
DESCRIPTION_描述nvarchar(4000)描述
TYPE_类型nvarchar(255)附件类型
TASK_ID_任务实例IDnvarchar(64)节点实例ID
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
URL_URL_nvarchar(4000)附件地址
CONTENT_ID_字节表的IDnvarchar(64)ACT_GE_BYTEARRAY的ID
历史意见表( act_hi_comment )
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)主键ID
TYPE_类型nvarchar(255)类型:event(事件)comment(意见)
TIME_时间datetime填写时间’
USER_ID_用户IDnvarchar(64)填写人
TASK_ID_节点任务IDnvarchar(64)节点实例ID
PROC_INST_ID_流程实例IDnvarchar(255)流程实例ID
ACTION_行为类型nvarchar(64)见备注1
MESSAGE_基本内容nvarchar(4000)用于存放流程产生的信息,比如审批意见
FULL_MSG_全部内容varbinary(max)附件地址
历史详情表( act_hi_detail )

流程中产生的变量详细,包括控制流程流转的变量,业务表单中填写的流程需要用到的变量等。

字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)主键
TYPE_类型nvarchar(255)见备注2
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
EXECUTION_ID_执行实例IDnvarchar(64)执行实例ID
TASK_ID_任务实例IDnvarchar(64)任务实例ID
ACT_INST_ID_节点实例IDnvarchar(64)ACT_HI_ACTINST表的ID
NAME_名称nvarchar(255)名称
VAR_TYPE_参数类型nvarchar(255)见备注3
REV_乐观锁intVersion
TIME_时间戳datetime创建时间
BYTEARRAY_ID_字节表IDnvarcharACT_GE_BYTEARRAY表的ID
DOUBLE_DOUBLE_double precision存储变量类型为Double
LONG_LONG_numeric存储变量类型为long
TEXT_TEXT_nvarchar存储变量值类型为String
TEXT2_TEXT2_nvarchar此处存储的是JPA持久化对象时,才会有值。此值为对象ID
历史流程人员表( act_ru_identitylink )

任务参与者数据表。主要存储历史节点参与者的信息

字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)ID_
GROUP_ID_组IDnvarchar(255)组ID
TYPE_类型nvarchar(255)备注4
USER_ID_用户IDnvarchar(255)用户ID
TASK_ID_节点实例IDnvarchar(64)节点实例ID
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
历史流程实例表(act_hi_procinst)
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)主键ID
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
BUSINESS_KEY_业务主键nvarchar(255)业务主键,业务表单的ID
PROC_DEF_ID_流程定义IDnvarchar(64)流程定义ID
START_TIME_开始时间datetime开始时间
END_TIME_结束时间datetime结束时间
DURATION_耗时Numeric(19)耗时
START_USER_ID_起草人nvarchar(255)起草人
START_ACT_ID_开始节点IDnvarchar(255)起草环节ID
END_ACT_ID_结束节点IDnvarchar(255)结束环节ID
SUPER_PROCESS_INSTANCE_ID_父流程实例IDnvarchar(64)父流程实例ID
DELETE_REASON_删除原因nvarchar(4000)删除原因
历史任务实例表( act_hi_taskinst )
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)主键ID
PROC_DEF_ID_流程定义IDnvarchar(64)流程定义ID
TASK_DEF_KEY_节点定义IDnvarchar(255)节点定义ID
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
EXECUTION_ID_执行实例IDnvarchar(64)执行实例ID
NAME_名称varchar(255)名称
PARENT_TASK_ID_父节点实例IDnvarchar(64)父节点实例ID
DESCRIPTION_描述nvarchar(400)描述
OWNER_实际签收人 任务的拥有者nvarchar(255)签收人(默认为空,只有在委托时才有值)
ASSIGNEE_签收人或被委托nvarchar(255)签收人或被委托
START_TIME_开始时间datetime开始时间
CLAIM_TIME_提醒时间datetime提醒时间
END_TIME_结束时间datetime结束时间
DURATION_耗时numeric(19)耗时
DELETE_REASON_删除原因nvarchar(4000)删除原因(completed,deleted)
PRIORITY_优先级别int优先级别
DUE_DATE_过期时间datetime过期时间,表明任务应在多长时间内完成
FORM_KEY_节点定义的formkeynvarchar(255)desinger节点定义的form_key属性
历史变量表( act_hi_varinst )
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)ID_
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
EXECUTION_ID_执行实例IDnvarchar(255)执行实例ID
TASK_ID_任务实例IDnvarchar(64)任务实例ID
NAME_名称nvarchar(64)参数名称(英文)
VAR_TYPE_参数类型varchar(255)备注5
REV_乐观锁nvarchar(64)乐观锁 Version
BYTEARRAY_ID_字节表IDnvarchar(400)ACT_GE_BYTEARRAY表的主键
DOUBLE_DOUBLE_nvarchar(255)存储DoubleType类型的数据
LONG_LONG_nvarchar(255)存储LongType类型的数据
TEXT_TEXT_datetime备注6
TEXT2_TEXT2_datetime此处存储的是JPA持久化对象时,才会有值。此值为对象ID
用户组信息表( act_id_group )
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)主键ID
REV_乐观锁int乐观锁Version
NAME_名称nvarchar(255)组名称
TYPE_类型nvarchar(255)类型
用户扩展信息表( act_id_info )
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)主键ID
REV_乐观锁int乐观锁Version
USER_ID_用户IDnvarchar(64)
TYPE_类型nvarchar(64)
KEY_nvarchar(255)
VALUE_nvarchar(255)
PASSWORD_Image
PARENT_ID_nvarchar(255)
用户与分组对应信息表( act_id_membership )

用来保存用户的分组信息。

字段名称字段描述数据类型主键为空取值说明
USER_ID用户IDnvarchar(64)
GROUP_ID用户组IDnvarchar(64)
用户信息表( act_id_user )
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)主键ID
REV_乐观锁int乐观锁Version
FIRST_nvarchar(255)
LAST_nvarchar(255)
EMAIL_EMAIL_nvarchar(255)
PWD_密码nvarchar(255)
PICTURE_ID_图片IDnvarchar(64)
部署信息表( act_re_deployment )

部署流程定义时需要被持久化保存下来的信息。

字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)主键ID
NAME_部署名称nvarchar(255)部署文件名
CATEGORY_分类nvarchar(255)类别
DEPLOY_TIME_部署时间datetime部署时间
流程设计模型部署表( act_re_model )

流程设计器设计流程后,保存数据到该表。

字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)ID_
REV_乐观锁int乐观锁
NAME_名称nvarchar(255)名称
KEY_KEY_nvarchar(255)分类,例如:http://www.mossle.com/docs/activiti/
CATEGORY_分类nvarchar(255)分类
CREATE_TIME_创建时间datetime创建时间
LAST_UPDATE_TIME_最新修改时间datetime最新修改时间
VERSION_版本int版本
META_INFO_META_INFO_nvarchar(255)以json格式保存流程定义的信息
DEPLOYMENT_ID_部署IDnvarchar(255)部署ID
EDITOR_SOURCE_VALUE_ID_datetime
EDITOR_SOURCE_EXTRA_VALUE_ID_datetime
流程定义数据表( act_re_procdef )

业务流程定义数据表。此表和ACT_RE_DEPLOYMENT是多对一的关系,即,一个部署的bar包里可能包含多个流程定义文件,每个流程定义文件都会有一条记录在ACT_REPROCDEF表内,每个流程定义的数据,都会对于ACT_GE_BYTEARRAY表内的一个资源文件和PNG图片文件。和ACT_GE_BYTEARRAY的关联是通过程序用ACT_GE_BYTEARRAY.NAME与ACT_RE_PROCDEF.NAME_完成的,在数据库表结构中没有体现。

字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)ID_
REV_乐观锁int乐观锁
CATEGORY_分类nvarchar(255)流程定义的Namespace就是类别
NAME_名称nvarchar(255)名称
KEY_定义的KEYnvarchar(255)流程定义ID
VERSION_版本int版本
DEPLOYMENT_ID_部署表IDnvarchar(64)部署表ID
RESOURCE_NAME_bpmn文件名称nvarchar(4000)流程bpmn文件名称
DGRM_RESOURCE_NAME_png图片名称nvarchar(4000)流程图片名称
DESCRIPTION_描述nvarchar(4000)描述
HAS_START_FORM_KEY_是否存在开始节点formKeytinyintstart节点是否存在formKey 0否 1是
SUSPENSION_STATE_是否挂起tinyint1 激活 2挂起
act_ru_event_subscr
字段名称字段描述数据类型主键为空取值说明
ID_事件IDnvarchar(64)事件ID
REV_版本int乐观锁Version
EVENT_TYPE_事件类型nvarchar(255)事件类型
EVENT_NAME_事件名称nvarchar(255)事件名称
EXECUTION_ID_执行实例IDnvarchar(64)执行实例ID
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
ACTIVITY_ID_活动实例IDnvarchar(64)活动实例ID
CONFIGURATION_配置nvarchar(255)配置
CREATED_是否创建datetime默认值 当前系统时间戳CURRENT_TIMESTAMP
运行时流程执行实例表( act_ru_execution )
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)ID_
REV_乐观锁int乐观锁
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
BUSINESS_KEY_业务主键IDnvarchar(255)业务主键ID
PARENT_ID_父节点实例IDnvarchar(64)父节点实例ID
PROC_DEF_ID_流程定义IDnvarchar(64)流程定义ID
SUPER_EXEC_SUPER_EXEC_nvarchar(64)SUPER_EXEC_
ACT_ID_节点实例IDnvarchar(255)节点实例ID即ACT_HI_ACTINST中ID
IS_ACTIVE_是否存活tinyint是否存活
IS_CONCURRENT_是否并行tinyint是否为并行(true/false)
IS_SCOPE_IS_SCOPE_tinyintIS_SCOPE_
IS_EVENT_SCOPE_IS_EVENT_SCOPE_tinyintIS_EVENT_SCOPE_
SUSPENSION_STATE_是否挂起tinyint挂起状态 1激活 2挂起
CACHED_ENT_STATE_int
运行时流程人员表( act_ru_identitylink )

任务参与者数据表。主要存储当前节点参与者的信息。

字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)ID_
REV_乐观锁int乐观锁
GROUP_ID_组IDnvarchar(64)组ID
TYPE_类型nvarchar(255)备注7
USER_ID_用户IDnvarchar(64)用户ID
TASK_ID_节点实例IDnvarchar(64)节点实例ID
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
PROC_DEF_ID_流程定义IDnvarchar(255)流程定义ID
运行时定时任务数据表( act_ru_job )
字段名称字段描述数据类型主键为空取值说明
ID_标识nvarchar(64)标识
REV_版本int版本
TYPE_类型nvarchar(255)类型
LOCK_EXP_TIME_锁定释放时间datetime锁定释放时间
LOCK_OWNER_挂起者nvarchar(255)挂起者
EXCLUSIVE_bit
EXECUTION_ID_执行实例IDnvarchar(64)执行实例ID
PROCESS_INSTANCE_ID_流程实例IDnvarchar(64)流程实例ID
PROC_DEF_ID_流程定义IDnvarchar(64)流程定义ID
RETRIES_int
EXCEPTION_STACK_ID_异常信息IDnvarchar(64)异常信息ID
EXCEPTION_MSG_异常信息nvarchar(4000)异常信息
DUEDATE_到期时间datetime到期时间
REPEAT_重复nvarchar(255)重复
HANDLER_TYPE_处理类型nvarchar(255)处理类型
HANDLER_CFG_nvarchar(4000)标识
运行时任务节点表( act_ru_task )
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)ID_
REV_乐观锁int乐观锁
EXECUTION_ID_执行实例IDnvarchar(64)执行实例ID
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
PROC_DEF_ID_流程定义IDnvarchar(64)流程定义ID
NAME_节点定义名称nvarchar(255)节点定义名称
PARENT_TASK_ID_父节点实例IDnvarchar(64)父节点实例ID
DESCRIPTION_节点定义描述nvarchar(4000)节点定义描述
TASK_DEF_KEY_节点定义的KEYnvarchar(255)任务定义的ID
OWNER_实际签收人nvarchar(255)拥有者(一般情况下为空,只有在委托时才有值)
ASSIGNEE_签收人或委托人nvarchar(255)签收人或委托人
DELEGATION_委托类型nvarchar(64)备注8
PRIORITY_优先级别int优先级别,默认为:50
CREATE_TIME_创建时间datetime创建时间
DUE_DATE_过期时间datetime耗时
SUSPENSION_STATE_是否挂起int1代表激活 2代表挂起
运行时流程变量数据表( act_ru_variable )
字段名称字段描述数据类型主键为空取值说明
ID_ID_nvarchar(64)主键标识
REV_乐观锁int乐观锁
TYPE_类型nvarchar(255)备注9
NAME_名称nvarchar(255)变量名称
EXECUTION_ID_执行实例IDnvarchar(64)执行的ID
PROC_INST_ID_流程实例IDnvarchar(64)流程实例ID
TASK_ID_节点实例IDnvarchar(64)节点实例ID(Local)
BYTEARRAY_ID_字节表IDnvarchar(64)字节表的ID(ACT_GE_BYTEARRAY)
DOUBLE_DOUBLE_float存储变量类型为Double
LONG_LONG_numeric(19)存储变量类型为long
TEXT_TEXT_nvarchar(4000)'存储变量值类型为String 如此处存储持久化对象时,值jpa对象的class
TEXT2_TEXT2_nvarchar(4000)此处存储的是JPA持久化对象时,才会有值。此值为对象ID
  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值