文章目录

  • activiti使用详解
    • 快速开始
      • 在项目中添加如下依赖项
      • 修改application.yml配置文件和启动类
      • 在resources目录下新建processes目录并添加如下流程文件task_process.bpmn
      • 新建如下类
      • 编写测试类
    • activiti核心api
      • 流程引擎及服务
      • 流程存储服务 RepositoryService
        • api
      • 流程运行控制服务 RuntimeService
        • 启动流程变量管理
        • 流程实例与执行流
        • 流程触发
        • api
      • 任务管理服务 TaskService
        • TaskService对Task管理与流程控制
        • TaskService设置Task权限信息
        • TaskService设置Task附加信息
      • 身份管理服务 IdentityService
      • 表单服务管理 FormService
      • 历史管理服务 HistoryService
        • HistoryService构建历史查询对象
        • HistoryService删除历史操作
      • 其他管理服务
        • ManagementService
        • Job任务查询
        • 数据库相关操作
      • 异常策略 ActivitiEXception
    • bpmn文件详解
      • bpmn各节点详解
      • serviceTask使用的多种方式
      • 执行监听器( Execution listener)
    • Activiti 23张表
      • 23张表概述
      • 23张表详解
        • 二进制数据表(act_ge_bytearray)
        • 属性数据表(act_ge_property)
        • 历史节点表(act_hi_actinst)
        • 历史附件表( act_hi_attachment )
        • 历史意见表( act_hi_comment )
        • 历史详情表( act_hi_detail )
        • 历史流程人员表( act_ru_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 )

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: fullcheck-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 {@Overridepublic 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 {@Resourceprivate RuntimeService runtimeService;@Resourceprivate IdentityService identityService;@Resourceprivate TaskService taskService;@Resourceprivate 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 {@Autowiredprivate TaskProcessService taskProcessService;@Resourceprivate HistoryService historyService;/*** 测试试题重复进入试题重复仲裁,并在审核task时有驳回*/@Testpublic 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); // 此处进行模拟让试题重复,进入试题重复仲裁tasktaskProcessService.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());}}/*** 测试试题不重复,并在审核时有驳回*/@Testpublic 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); // 此处进行模拟让试题重复,进入试题重复仲裁tasktaskProcessService.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());}}/*** 测试试题重复,试题审核时没有驳回*/@Testpublic 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); // 此处进行模拟让试题重复,进入试题重复仲裁tasktaskProcessService.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>
Property Required? Description
mailServerHost no The hostname of your mail server (e.g. mail.mycorp.com). Default is localhost
mailServerPort yes, if not on the default port The port for SMTP traffic on the mail server. The default is 25
mailServerDefaultFrom no The default e-mail address of the sender of e-mails, when none is provided by the user. By default this is activiti@activiti.org
mailServerUsername if applicable for your server Some mail servers require credentials for sending e-mail. By default not set.
mailServerPassword if applicable for your server Some mail servers require credentials for sending e-mail. By default not set.
mailServerUseSSL if applicable for your server Some mail servers require ssl communication. By default set to false.
mailServerUseTLS if applicable for your server Some 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:
Property Required? Description
to yes The recipients if the e-mail. Multiple recipients are defined in a comma-separated list
from no The sender e-mail address. If not provided, the default configured from address is used.
subject no The subject of the e-mail.
cc no The cc’s of the e-mail. Multiple recipients are defined in a comma-separated list
bcc no The bcc’s of the e-mail. Multiple recipients are defined in a comma-separated list
charset no Allows to change the charset of the email, which is necessary for many non-English languages.
html no A piece of HTML that is the content of the e-mail.
text no The 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.
htmlVar no The 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.
textVar no The 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.
ignoreException no Whether an failure when handling the e-mail throws an ActivitiException. By default this is set to false.
exceptionVariableName no When 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 variablefoo = "FOO"; // pushes variable to execution contextexecution.setVariable("var1", "test"); // test access to execution instancebar // 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_subscr throwEvent、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_ 乐观锁 int Y Version(版本)
NAME_ 名称 nvarchar(255) Y 部署的文件名称,如:leave.bpmn.png,leave.bpmn20.xml
DEPLOYMENT_ID_ 部署ID nvarchar(64) Y 部署表ID
BYTES_ 字节 varbinary(max) Y 部署文件
GENERATED_ 是否是引擎生成 tinyint Y 0为用户生成,1为activiti生成

属性数据表(act_ge_property)

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

字段名称 字段描述 数据类型 主键 为空 取值说明
NAME_ 名称 nvarchar(64) schema.versionschema.historynext.dbid
VALUE_ nvarchar(300) 5.create(5.)
REV_ 乐观锁 int version

历史节点表(act_hi_actinst)

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

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID_ nvarchar(64)
PROC_DEF_ID_ 流程定义ID nvarchar(64)
PROC_INST_ID_ 流程实例ID nvarchar(64)
EXECUTION_ID_ 执行实例ID nvarchar(64)
ACT_ID_ 节点ID nvarchar(225) 节点定义ID
TASK_ID_ 任务实例ID nvarchar(64) 任务实例ID 其他节点类型实例ID在这里为空
CALL_PROC_INST_ID_ 调用外部的流程实例ID nvarchar(64) 调用外部流程的流程实例ID’
ACT_NAME_ 节点名称 nvarchar(225) 节点定义名称
ACT_TYPE_ 节点类型 nvarchar(225) 如startEvent、userTask
ASSIGNEE_ 签收人 nvarchar(64) 节点签收人
START_TIME_ 开始时间 datetime 2013-09-15 11:30:00
END_TIME_ 结束时间 datetime 2013-09-15 11:30:00
DURATION_ 耗时 numeric(19,0) 毫秒值

历史附件表( act_hi_attachment )

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID_ nvarchar(64) 主键ID
REV_ 乐观锁 integer Version
USER_ID_ 用户ID nvarchar(255) 用户ID
NAME_ 名称 nvarchar(255) 附件名称
DESCRIPTION_ 描述 nvarchar(4000) 描述
TYPE_ 类型 nvarchar(255) 附件类型
TASK_ID_ 任务实例ID nvarchar(64) 节点实例ID
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例ID
URL_ URL_ nvarchar(4000) 附件地址
CONTENT_ID_ 字节表的ID nvarchar(64) ACT_GE_BYTEARRAY的ID

历史意见表( act_hi_comment )

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID_ nvarchar(64) 主键ID
TYPE_ 类型 nvarchar(255) 类型:event(事件)comment(意见)
TIME_ 时间 datetime 填写时间’
USER_ID_ 用户ID nvarchar(64) 填写人
TASK_ID_ 节点任务ID nvarchar(64) 节点实例ID
PROC_INST_ID_ 流程实例ID nvarchar(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_ 流程实例ID nvarchar(64) 流程实例ID
EXECUTION_ID_ 执行实例ID nvarchar(64) 执行实例ID
TASK_ID_ 任务实例ID nvarchar(64) 任务实例ID
ACT_INST_ID_ 节点实例ID nvarchar(64) ACT_HI_ACTINST表的ID
NAME_ 名称 nvarchar(255) 名称
VAR_TYPE_ 参数类型 nvarchar(255) 见备注3
REV_ 乐观锁 int Version
TIME_ 时间戳 datetime 创建时间
BYTEARRAY_ID_ 字节表ID nvarchar ACT_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_ 组ID nvarchar(255) 组ID
TYPE_ 类型 nvarchar(255) 备注4
USER_ID_ 用户ID nvarchar(255) 用户ID
TASK_ID_ 节点实例ID nvarchar(64) 节点实例ID
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例ID

历史流程实例表(act_hi_procinst)

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID_ nvarchar(64) 主键ID
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例ID
BUSINESS_KEY_ 业务主键 nvarchar(255) 业务主键,业务表单的ID
PROC_DEF_ID_ 流程定义ID nvarchar(64) 流程定义ID
START_TIME_ 开始时间 datetime 开始时间
END_TIME_ 结束时间 datetime 结束时间
DURATION_ 耗时 Numeric(19) 耗时
START_USER_ID_ 起草人 nvarchar(255) 起草人
START_ACT_ID_ 开始节点ID nvarchar(255) 起草环节ID
END_ACT_ID_ 结束节点ID nvarchar(255) 结束环节ID
SUPER_PROCESS_INSTANCE_ID_ 父流程实例ID nvarchar(64) 父流程实例ID
DELETE_REASON_ 删除原因 nvarchar(4000) 删除原因

历史任务实例表( act_hi_taskinst )

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID_ nvarchar(64) 主键ID
PROC_DEF_ID_ 流程定义ID nvarchar(64) 流程定义ID
TASK_DEF_KEY_ 节点定义ID nvarchar(255) 节点定义ID
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例ID
EXECUTION_ID_ 执行实例ID nvarchar(64) 执行实例ID
NAME_ 名称 varchar(255) 名称
PARENT_TASK_ID_ 父节点实例ID nvarchar(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_ 节点定义的formkey nvarchar(255) desinger节点定义的form_key属性

历史变量表( act_hi_varinst )

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID_ nvarchar(64) ID_
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例ID
EXECUTION_ID_ 执行实例ID nvarchar(255) 执行实例ID
TASK_ID_ 任务实例ID nvarchar(64) 任务实例ID
NAME_ 名称 nvarchar(64) 参数名称(英文)
VAR_TYPE_ 参数类型 varchar(255) 备注5
REV_ 乐观锁 nvarchar(64) 乐观锁 Version
BYTEARRAY_ID_ 字节表ID nvarchar(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_ 用户ID nvarchar(64)
TYPE_ 类型 nvarchar(64)
KEY_ nvarchar(255)
VALUE_ nvarchar(255)
PASSWORD_ Image
PARENT_ID_ nvarchar(255)

用户与分组对应信息表( act_id_membership )

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

字段名称 字段描述 数据类型 主键 为空 取值说明
USER_ID 用户ID nvarchar(64)
GROUP_ID 用户组ID nvarchar(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_ 图片ID nvarchar(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_ 部署ID nvarchar(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_ 定义的KEY nvarchar(255) 流程定义ID
VERSION_ 版本 int 版本
DEPLOYMENT_ID_ 部署表ID nvarchar(64) 部署表ID
RESOURCE_NAME_ bpmn文件名称 nvarchar(4000) 流程bpmn文件名称
DGRM_RESOURCE_NAME_ png图片名称 nvarchar(4000) 流程图片名称
DESCRIPTION_ 描述 nvarchar(4000) 描述
HAS_START_FORM_KEY_ 是否存在开始节点formKey tinyint start节点是否存在formKey 0否 1是
SUSPENSION_STATE_ 是否挂起 tinyint 1 激活 2挂起

act_ru_event_subscr

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ 事件ID nvarchar(64) 事件ID
REV_ 版本 int 乐观锁Version
EVENT_TYPE_ 事件类型 nvarchar(255) 事件类型
EVENT_NAME_ 事件名称 nvarchar(255) 事件名称
EXECUTION_ID_ 执行实例ID nvarchar(64) 执行实例ID
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例ID
ACTIVITY_ID_ 活动实例ID nvarchar(64) 活动实例ID
CONFIGURATION_ 配置 nvarchar(255) 配置
CREATED_ 是否创建 datetime 默认值 当前系统时间戳CURRENT_TIMESTAMP

运行时流程执行实例表( act_ru_execution )

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID_ nvarchar(64) ID_
REV_ 乐观锁 int 乐观锁
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例ID
BUSINESS_KEY_ 业务主键ID nvarchar(255) 业务主键ID
PARENT_ID_ 父节点实例ID nvarchar(64) 父节点实例ID
PROC_DEF_ID_ 流程定义ID nvarchar(64) 流程定义ID
SUPER_EXEC_ SUPER_EXEC_ nvarchar(64) SUPER_EXEC_
ACT_ID_ 节点实例ID nvarchar(255) 节点实例ID即ACT_HI_ACTINST中ID
IS_ACTIVE_ 是否存活 tinyint 是否存活
IS_CONCURRENT_ 是否并行 tinyint 是否为并行(true/false)
IS_SCOPE_ IS_SCOPE_ tinyint IS_SCOPE_
IS_EVENT_SCOPE_ IS_EVENT_SCOPE_ tinyint IS_EVENT_SCOPE_
SUSPENSION_STATE_ 是否挂起 tinyint 挂起状态 1激活 2挂起
CACHED_ENT_STATE_ int

运行时流程人员表( act_ru_identitylink )

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

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID_ nvarchar(64) ID_
REV_ 乐观锁 int 乐观锁
GROUP_ID_ 组ID nvarchar(64) 组ID
TYPE_ 类型 nvarchar(255) 备注7
USER_ID_ 用户ID nvarchar(64) 用户ID
TASK_ID_ 节点实例ID nvarchar(64) 节点实例ID
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例ID
PROC_DEF_ID_ 流程定义ID nvarchar(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_ 执行实例ID nvarchar(64) 执行实例ID
PROCESS_INSTANCE_ID_ 流程实例ID nvarchar(64) 流程实例ID
PROC_DEF_ID_ 流程定义ID nvarchar(64) 流程定义ID
RETRIES_ int
EXCEPTION_STACK_ID_ 异常信息ID nvarchar(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_ 执行实例ID nvarchar(64) 执行实例ID
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例ID
PROC_DEF_ID_ 流程定义ID nvarchar(64) 流程定义ID
NAME_ 节点定义名称 nvarchar(255) 节点定义名称
PARENT_TASK_ID_ 父节点实例ID nvarchar(64) 父节点实例ID
DESCRIPTION_ 节点定义描述 nvarchar(4000) 节点定义描述
TASK_DEF_KEY_ 节点定义的KEY nvarchar(255) 任务定义的ID
OWNER_ 实际签收人 nvarchar(255) 拥有者(一般情况下为空,只有在委托时才有值)
ASSIGNEE_ 签收人或委托人 nvarchar(255) 签收人或委托人
DELEGATION_ 委托类型 nvarchar(64) 备注8
PRIORITY_ 优先级别 int 优先级别,默认为:50
CREATE_TIME_ 创建时间 datetime 创建时间
DUE_DATE_ 过期时间 datetime 耗时
SUSPENSION_STATE_ 是否挂起 int 1代表激活 2代表挂起

运行时流程变量数据表( act_ru_variable )

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID_ nvarchar(64) 主键标识
REV_ 乐观锁 int 乐观锁
TYPE_ 类型 nvarchar(255) 备注9
NAME_ 名称 nvarchar(255) 变量名称
EXECUTION_ID_ 执行实例ID nvarchar(64) 执行的ID
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例ID
TASK_ID_ 节点实例ID nvarchar(64) 节点实例ID(Local)
BYTEARRAY_ID_ 字节表ID nvarchar(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

activiti使用详解相关推荐

  1. springboot activiti 配置项详解

    asyncExecutorEnabled属性设置设置true后将代替那些老的Job executor spring.activiti.async-executor-enabled=false spri ...

  2. activiti:initiator详解

    在activiti的startEvent中,我们可以通过initiator属性来设置一个变量,然后启动流程时会将authenticatedUserId(流程启动者)的值设置为activiti:init ...

  3. activiti使用详解(一)

    简单的api程序示例(maven工程): 下载链接: http://pan.baidu.com/s/1pJ1TfgZ https://github.com/frederikheremans/activ ...

  4. 工作流引擎 Activiti 入门详解

    点击关注公众号,利用碎片时间学习 1. 什么是工作流 1.1 工作流介绍 工作流(Workflow),就是通过计算机对业务流程自动化执行管理.它主要解决的是"使在多个参与者之间按照某种预定义 ...

  5. 详解工作流框架Activiti的服务架构和组件

    摘要:通过这篇文章,可以对工作流有一个基本的认识,为后续工作流框架Activiti的学习打下坚实的基础. 本文分享自华为云社区<BPMN工作流的基本概念!详解工作流框架Activiti的服务架构 ...

  6. Activiti工作流学习之流程图应用详解

    Activiti工作流学习之流程图应用详解 1.目的 了解Activiti工作流是怎样应用流程图的. 2.环境准备 2.1.相关软件及版本 jdk版本:Jdk1.7及以上 IDE:eclipse 数据 ...

  7. bpmn如何查看代码 idea_IDEA教程之Activiti插件图文详解

    本文作者:Spring_ZYL 文章来源:https://blog.csdn.net/gozhuyinglong 版权声明:本文版权归作者所有,转载请注明出处 一.安装Activiti插件 1.搜索插 ...

  8. 基于easyui开发Web版Activiti流程定制器详解(二)——文件列表

     上一篇我们介绍了目录结构,这篇给大家整理一个文件列表以及详细说明,方便大家查找文件. 由于设计器文件主要保存在wf/designer和js/designer目录下,所以主要针对这两个目录进行详细 ...

  9. SpringBoot注解最全详解(整合超详细版本)

    今日推荐强制双休!腾讯调整加班机制,21 点前必须离开工位 使用雪花id或uuid作为Mysql主键,被老板怼了一顿! 盘点 12 个 GitHub 上的高仿项目 CTO 说了,用错 @Autowir ...

最新文章

  1. Tomcat 初始化端点错误--Error initializing endpoint
  2. 前端学习(1049):todolist正在进行和已经完成阶段2
  3. 电脑屏保海底世界_炸弹测深出来的海底一万米,都藏有何种玄机?
  4. php 生成等比例缩略图,PHP实现原比例生成缩略图的方法
  5. 详解Python中的算术乘法、数组乘法与矩阵乘法
  6. Problem E: 分数统计
  7. Filecoin网络存储容量迎来3 EiB时刻
  8. 地图上如何量方位角_野外怎样确定方位 户外辨别方向和位置的方法有哪些?...
  9. TI - MCU - MSP430使用指南1 - MSP430简介及选型指南
  10. 服务器安全加固三件套
  11. Java面试基础知识,一次哔哩哔哩面试经历
  12. 从业务出发,来谈谈策略模式
  13. Devign: Effective Vulnerability Identification byLearning Comprehensive Program Semantics viaGraph
  14. Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'redis.maxIdle' in stri
  15. QT在线简体中文文档
  16. 关于旁路由设置后,主路由WIFI无法上网的问题
  17. h5py OSError: Unable to open file (unable to lock file, errno = 11, error message = ‘Resource tempor
  18. SCAU计算机网络综合性实验
  19. 【SpringBoot项目】SpringBoot项目-瑞吉外卖【day02】员工管理业务开发
  20. HoloLens 2 系列视频来袭

热门文章

  1. 如何使linux用户下次登录强制修改密码
  2. iOS 开发之优化电量
  3. 怎么给图片加上红圈,红框,红箭头标重点等?还有添加文字
  4. 数组指针——指向数组对象的指针
  5. +、-、*、/复数与整数运算符重载
  6. [论文总结]:faster cnns with direct sparse convolutions and guided pruning 直接稀疏卷积和引导剪枝
  7. 《信息安全工程师教程》学习笔记02(第二章 密码学基础与应用—DES算法)
  8. Redis5搭建集群
  9. 实习日记 7.10
  10. 全心全意的服务,让转行的我能够成功斩获自己心仪的offer——享学课堂