IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> activiti6工作流开发 -> 正文阅读

[大数据]activiti6工作流开发

activiti6工作流开发


转载请标明出处:鸭梨的药丸哥

工作流数据库准备

activiti6依赖于SQL数据库,要运行activiti6需要准备好SQL数据库,在activiti部署前要求准备好表的创建。

Activiti有3种表创建方式:

  • DB_SCHEMA_UPDATE_FALSE //不能自动创建表,需要表存在
  • DB_SCHEMA_UPDATE_CREATE_DROP //启动引擎时创建表,关闭引擎时删除表
  • DB_SCHEMA_UPDATE_TRUE//如果表不存在,自动创建表

Activiti有3种启动方式:

  • 通过编码的方式,ProcessEngineConfiguration硬编码配置信息,然后启动activiti
  • 自定义配置文件方式,读过读取指定指定xml配置文件的配置启动activiti
  • 通过默认方式(读取classpath路径下activiti.cfg.xml文件)

启动方式一

通过编码的方式启动activiti,启动时注意表的创建方式,如果需要完全初始化的方式启动,请使用DB_SCHEMA_UPDATE_CREATE_DROP

//生成工作流需要的表
public void initTable(){
    //流程引擎的配置对象,这种方式不需要配置文件
    ProcessEngineConfiguration engineConfiguration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
    //加载配置,然后需要得到工作流的核心对象
    ProcessEngine processEngine = engineConfiguration.setJdbcDriver("com.mysql.cj.jdbc.Driver")//驱动
        .setJdbcUrl("jdbc:mysql://localhost:3306/activiti?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false")//jdbc url
        .setJdbcUsername("root")//数据库账号
        .setJdbcPassword("xxx")//数据库密码
        .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE) //设置表的更新(这里使用如果表不存在,自动创建表)
        .buildProcessEngine();  //创建引擎

}

启动方式二

添加配置信息
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	   http://www.springframework.org/schema/beans/spring-beans.xsd">
    
	<!-- 创建工作流引擎的核心对象,id的名称不可以修改-->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!-- 加载数据源 -->
        <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti?serverTimezone=UTC&amp;useUnicode=true&amp;characterEncoding=utf8"></property>
        <property name="jdbcUsername" value="root"></property>
        <property name="jdbcPassword" value="xxxxx"></property>
        <!-- 设置数据库表的更新-->
        <property name="databaseSchemaUpdate" value="true"></property>
    </bean>

</beans>
使用指定配置文件
//生成工作流需要的表
public void initTable(){
    //指定加载配置
    ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
    //创建引擎
    ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();

}

启动方式三

//如果没有初始引擎,会读取activiti.cfg.xml文件去创建引擎,并返回
private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

表的生成

日志表:

act_evt_log 存储事件处理日志,方便管理员跟踪处理

通用数据表:

act_ge_bytearray 二进制数据表,一些文件存在这个表。

act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录

历史数据表

act_hi_actinst 历史节点表

act_hi_attachment 历史附件表

act_hi_comment 历史意见表

act_hi_detail 历史详情表,提供历史变量的查询

act_hi_identitylink 历史流程人员表

act_hi_procinst 历史流程实例表

act_hi_taskinst 历史任务实例表

act_hi_varinst 历史变量表

用户组织表:

act_id_group 用户组信息表

act_id_info 用户扩展信息表

act_id_membership 用户与用户组对应信息表

act_id_user 用户信息表

资源流程规则表:

act_procdef_info 流程定义信息

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 运行时流程变量数据表

绘制流程图

如果是idea2019版本之前的可以使用actiBPM插件进行绘制。

如果是idea2019版本之后,则需要使用activiti bpmn visualizer等其他插件进行代替。

下面步骤将按照这个流程进行。

请添加图片描述

流程部署

使用bpmn文件部署流程

//部署流程
public String deploy(){
    //通过流程引擎对象得到部署的服务层对象
    RepositoryService repositoryService = processEngine.getRepositoryService();
    //调用部署(部署过程中会自动生成流程声明)
    Deployment deploy = repositoryService.createDeployment()
        .addClasspathResource("store.bpmn")  //部署的流程图
        .name("入库审批流程")  //部署流程的名字(名字记录到act_re_procdef)
        .deploy();  //部署
    
    return deploy.getId();//返回部署id(对应act_re_deployment中的id)
}

使用压缩包部署流程

使用压缩包时,压缩包里面必须有bpmn文件,否则是无法进行解压部署的

//部署流程
public String deploy(){
    RepositoryService repositoryService = processEngine.getRepositoryService();
    //获取classpath路径下的store.zip文件输入流
    InputStream in = this.getClass().getClassLoader().getResourceAsStream("store.zip");
    //封装成ZipInputStream
    ZipInputStream zipInputStream = new ZipInputStream(in);
    
    Deployment deploy = repositoryService.createDeployment()
        .addZipInputStream(zipInputStream)  //zip资源
        .name("入库审批流程")    //部署流程的名字
        .deploy();  //部署

    return deploy.getId();
}

流程部署分析

  • 在流程定义数据表(act_re_procdef)中生成流程声明,id是流程图的id:版本:序列号(系统生成),KEY是流程图的id。
  • 在二进制数据表(act_ge_bytearray)中保存数据文件,如bpmn,png(流程图片会自动生成)等
  • 在部署信息表(act_re_deployment) 中生成一条部署信息

流程启动

每启动一个流程,那么就会在数据库生成相应的流程实例信息。

通过流程声明KEY启动

流程声明KEY于定义该流程声明的流程图id一致

//启动流程
public void start(){
    //需要得到运行时的服务层对象
    RuntimeService runtimeService = processEngine.getRuntimeService();
    //根据key来启动流程
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess_1");//流程图的id(act_re_procdef中的KEY)
    //得到流程信息
    System.out.println("实例ID:"+processInstance.getId());//对于act_ru_execution中的id
    System.out.println("流程定义ID:"+processInstance.getProcessDefinitionId());
}

通过流程定义ID启动

//启动流程
public void start(){
    //需要得到运行时的服务层对象
    RuntimeService runtimeService = processEngine.getRuntimeService();
    //根据key来启动流程
    ProcessInstance processInstance = runtimeService.startProcessInstanceById("myProcess_1:1:2504");//act_re_procdef中的id
    
    //得到流程信息
    System.out.println("实例ID:"+processInstance.getId());
    System.out.println("流程定义ID:"+processInstance.getProcessDefinitionId());
}

流程启动分析

当流程启动后,会生成流程实例信息,act_ru_execution记录基本的流程实例信息,act_ru_task记录当前有哪些任务在运行,act_ru_identitylink记录任务相关的人物信息。

  • 在运行时流程任务表(act_ru_task),跟新执行任务信息。其中act_ru_task的PROC_INST_ID_记录这该任务与哪个流程实例信息绑定。PROC_DEF_ID_记录的是流程声明的id(act_re_procdef中的ID)
  • 跟新运行时流程执行表(act_ru_execution),跟新现在正在执行的流程实例信息。
  • 跟新执行主体相关信息表(act_ru_identitylink),跟新执行任务的相关人物信息
  • 在历史流程人员表(act_hi_identitylink)生成一条历史记录

任务查找

通过任务代理人名称查询

//查询任务
public void find(){
    //得到任务的服务层对象
    TaskService taskService = processEngine.getTaskService();
    List<Task> taskList = taskService.createTaskQuery()
        .taskAssignee("维修工")//查询条件(根据代理人查询)
        .list(); 
    for (Task task : taskList) {
        System.out.println("任务ID:"+task.getId());
        System.out.println("任务名称:"+task.getName());
        System.out.println("执行者:"+task.getAssignee());
        System.out.println("流程定义ID:"+task.getProcessDefinitionId());
    }
}

通过流程实例id查询

根据正在运行的流程实例的id查找当前要实现的任务

public void find(){
        //得到任务的服务层对象
        TaskService taskService = processEngine.getTaskService();

        List<Task> taskList = taskService.createTaskQuery()
                                .processInstanceId("5001")//跟act_ru_execution的id相同
                                .list();

        for (Task task : taskList) {
            System.out.println("任务ID:"+task.getId());
            System.out.println("任务名称:"+task.getName());
            System.out.println("执行者:"+task.getAssignee());
            System.out.println("流程定义ID:"+task.getProcessDefinitionId());
        }
    }

任务执行

通过任务id执行任务

//完成任务
public void complete(){
    //得到任务服务层的对象
    TaskService taskService = processEngine.getTaskService();
    taskService.complete("5004");//任务id
}

任务执行分析

  • 如果当前流程实例的所有任务已经完成,那么运行时流程执行实例表(act_ru_execution)流程实例信息将会销毁,以及对应在运行时任务节点表(act_ru_task)的任务信息销毁(因为已经执行完了),运行时流程人员表(act_ru_identitylink)对应的流程人员会被销毁(任务完成了,不需要了)。

  • 如果当前流程实例尚未完成,那么将会跟新运行时任务节点表(act_ru_task)的任务信息,并更新运行时流程人员表(act_ru_identitylink)对应的流程人员

流程变量

流程实例能捆绑变量,如:提交请假申请(往往会捆绑一个请假单),通过申请单的id那么就可以获取申请了多少假期(申请单应该存储在另一个业务系统中)。

为了能捆绑第三方业务系统的信息,activiti提供了流程执行的过程中捆绑变量的功能,通过进行变量的捆绑,每个流程实例都可以拥有独自的变量信息。

流程中的变量会跟随流程的进行而传递,也就是说上一个任务设置的变量在下一个任务中也都能获取,不会因为流程任务状态更新而导致变量丢失不见的问题

假设现在在第三方业务系统上有一个账单信息实体类,必须实现序列化

@Data
@EqualsAndHashCode(callSuper = false)
@AllArgsConstructor
public class RepairBillDetail implements Serializable {
    //序列化id
    private static final long serialVersionUID = -1914045242557039080L;
    
    private Long id;    //维修单id

    private String repairInfo;     //账单描述信息

    private BigDecimal price;  //维修价格
}

启动流程时传递变量

//启动时捆绑变量
public void startByVar(){
    //账单实体类
    RepairBillDetail repairBillDetail = new RepairBillDetail(10001L, "维修账单", BigDecimal.valueOf(500.5));

    //构建变量
    HashMap<String, Object> map = new HashMap<>();
    map.put("bill",repairBillDetail);

    RuntimeService runtimeService = processEngine.getRuntimeService();
    //根据流程声明ID启动,并传递变量variables
    ProcessInstance processInstance = runtimeService.startProcessInstanceById("myProcess_1:1:2504",map);

    //得到流程信息
    System.out.println("实例ID:"+processInstance.getId());
    System.out.println("流程定义ID:"+processInstance.getProcessDefinitionId());
    
}

指定任务传递变量

public void setVarByTaskId(){
        TaskService taskService = processEngine.getTaskService();
        String taskId = "5012";
        RepairBillDetail repairBillDetail = new RepairBillDetail(10001L, "维修账单2", BigDecimal.valueOf(500.5));
    	//根据任务id设置变量(注意,该变量将会在整个流程实例中生效)
        taskService.setVariable(taskId,"bill2",repairBillDetail);
        
        Map<String, Object> variables = taskService.getVariables(taskId);
        System.out.println(variables);
    }

完成任务时传递变量

public void completeAndSetVar(){
    RepairBillDetail repairBillDetail = new RepairBillDetail(10001L, "维修账单3", BigDecimal.valueOf(500.5));
    HashMap<String, Object> map = new HashMap<>();
    map.put("bill",repairBillDetail);
    map.put("var2","字符串变量");
    map.put("var3",100);

    String taskId = "5012";
    TaskService taskService = processEngine.getTaskService();
    //根据任务id完成任务,并设置var
    taskService.complete(taskId,map);
}

获取变量

public void getVarByTaskId(){
	//根据任务id获取变量,何时都能获取变量,只需要传递当前正在执行的任务id就能获取到上一个任务设置的变量
    Map<String, Object> variables = taskService.getVariables(taskId);
    System.out.println(variables);
}

变量存储分析

  • 普通的变量是存储在运行时流程变量数据表(act_ru_variable),比如Long,String等
  • 对象变量是存储在运行时流程变量数据表(act_ru_variable),二进制数据表(act_ge_bytearray)这两张表中,其中act_ru_variable记录着变量的详情,而对象序列化数据是存储在act_ge_bytearray

变量在流程中使用案例

画图插件的问题

在IDEA2020版本后插件actiBPM已经不能兼容使用了,这里我使用画图工具activiti BPMN visualizer

这里使用activiti BPMN visualizer插件进行流程图的开发。

请假示例

画下面流程图,其中请假的人使用变量 s t u N a m e 来 代 替 , 班 主 任 使 用 {stuName}来代替,班主任使用 stuName使{tchName}来动态指定,系主任使用${deanName}指定,应该注意的是这些变量应该是来自第三方业务系统的。

请添加图片描述

简单的流程代码

//请假工作流示例
public class LeaveFlow {

    //流程引擎
    private final ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

    //部署
    public Deployment deploy(String resource, String name){
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("test.bpmn20.xml")
                .name("请假申请流程")
                .deploy();
        System.out.println("部署信息id:"+deployment.getId());
        return deployment;
    }


    //启动流程
    public ProcessInstance start(ProcessDefinition definition,String assignee){
        RuntimeService runtimeService = processEngine.getRuntimeService();

        HashMap<String, Object> map = new HashMap<>();
        map.put("stuName",assignee);//谁启动流程就添加谁为请假人员
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(definition.getId(),map);

        return processInstance;
    }

    //成为任务
    public void completTask(String taskId, Map var){
        TaskService taskService = processEngine.getTaskService();
        taskService.complete(taskId,var);
    }

    //寻找任务
    public Task findTask(ProcessInstance instance,String assignee){
        TaskService taskService = processEngine.getTaskService();

        Task task = taskService.createTaskQuery()
                                .processInstanceId(instance.getId())
                                .taskAssignee(assignee)
                                .singleResult();
        return task;
    }

    public ProcessDefinition findProcessDefinition(Deployment deployment){
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                                                            .deploymentId(deployment.getId())
                                                            .singleResult();
        return processDefinition;
    }

    public Deployment findDeployment(String deployName){
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //根据deployment名字查找部署信息
        Deployment deployment = repositoryService.createDeploymentQuery()
                                            .deploymentName(deployName)
                                            .singleResult();
        return deployment;
    }

    public static void main(String[] args) {
        LeaveFlow leaveFlow = new LeaveFlow();
        String resure = "test.bpmn20.xml";
        String deployName = "请假申请流程";
        //部署
        //Deployment deploy = leaveFlow.deploy(resure, deployName);
        //部署过可以通过,部署名获取deployment
        Deployment deploy = leaveFlow.findDeployment(deployName);
        //查找流程定义
        ProcessDefinition processDefinition = leaveFlow.findProcessDefinition(deploy);

        //启动流程(张三点击请假,启动流程)
        ProcessInstance processInstance = leaveFlow.start(processDefinition, "张三");
        //查找张三任务
        Task task = leaveFlow.findTask(processInstance, "张三");

        //设置变量
        HashMap hashMap = new HashMap() {{
            put("days",5); //设置申请天数(张三填)
            put("tchName","陈老师");  //设置老师(张三的老师)
        }};
        //张三完成任务
        leaveFlow.completTask(task.getId(),hashMap);

        //查找陈老师的任务
        Task task2 = leaveFlow.findTask(processInstance, "陈老师");
        //设置变量
        hashMap.put("deanName","张主任");
        //陈老师完成任务
        leaveFlow.completTask(task2.getId(),hashMap);

        //查找张主任的任务
        Task task3 = leaveFlow.findTask(processInstance, "张主任");
        //完成审批
        if (task3!=null)leaveFlow.completTask(task3.getId(),null);
    }
}

流程分析

步骤流程如下:

  • 部署,在(act_re_deployment)(act_re_procdef)(act_ge_bytearray)分别生成一条或条信息。分别是流程部署信息(包含部署id,部署名称等),流程定义(包含定义id,流程图识别符key,),二进制数据(包含两条,分别是图片,流程声明文件)
  • 启动流程,通过流程定义的id或者流程定义中的key(流程图id)启动流程,生成一个流程实例。流程实例存储在(act_ru_execution),而当前正要执行的任务存放在(act_ru_task)。
  • 执行任务,执行任务需要指定要实现任务的id,通常通过流程实例id执行人name去锁定某个流程实例中的任务节点,锁定任务节点后,完成任务。
  • 条件判断和变量赋值,不同的任务有不同的判断条件和变量,根据条件去确定下一个任务节点,条件中的变量可以在流程执行的过程中进行添加,如条件判断变量,任务执行者变量等。

流程网关

activiti中有两种流程网关,一种是并行网关,一种是排他网关,包含网关,事件网关。

排他网关

排他官网流程跟上面的请假示例相识,是根据条件来判断流程执行步骤,设置变量即可能进行流程判断了。

请添加图片描述

并行网关

并行网关没有判断条件,当请假任务完成后,将会同时生成两个任务节点,要完成两个任务节点才能进入下一任务节点。如下,要完成班主任审核,系主任审核才能完成请假流程。

请添加图片描述

包含网关

包含网关是排他和并行的结合,如下:当满足请假天数days>3这个添加时,需要班主任和系主任同时审核,当days<=3时,只需要班主任审核。

请添加图片描述

流程任务

ServiceTask

服务任务ServiceTask,通过委派模式供activiti执行第三方任务代码。

请添加图片描述

委派监听类如下:

/**
 * @author liangwy
 * @see org.activiti.engine.delegate.JavaDelegate
 * @since 2022-4-29
 */
public class ServiceTask implements JavaDelegate {

    @Autowired
    private MyService myService;

    //委派任务(实现JavaDelegate接口)
    @Override
    public void execute(DelegateExecution execution) throws Exception {

        //执行自己的业务逻辑
        myService.doSome();
        //设置流程变量,供下面的任务使用
        execution.setVariable("var","设置变量");

    }
}

MailTask

邮件发送任务,使用POP3邮件接受协议和SMTP邮件发送协议实现邮件发送。

添加配置信息

只需要在

<!--配置邮件服务器-->
<property name="mailServerHost" value="smtp.qq.com"/>
<property name="mailServerPort" value="465"/>
<!--默认来源,没设置来源时会用该默认值代替-->
<property name="mailServerDefaultFrom" value="xxxxx@qq.com"/>
<property name="mailServerUsername" value="xxxxx@qq.com"/>
<!--授权码-->
<property name="mailServerPassword" value="123456487"/>  
<property name="mailServerUseSSL" value="true"/>

画图

请添加图片描述

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-05-01 15:49:32  更:2022-05-01 15:52:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:10:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码