55.java项目-activiti实战项目(1)-activiti基本介绍

1.流程

1.1什么是流程?

流程就是按照一定设计规则执行的程序,例如公司的请假流程,报销流程等等.

1.2 我们怎么进行流程开发?

如果我们不借用框架的情况下进行流程开发,通常是在数据库表用一个状态的字段来对流程进行控制,比如请假流程,状态1是开始流程,填写了请假单,状态2是部门经理审批,状态3是总经理审批,状态4是人事存档.我们每个用户根据自己的角色筛选对应状态下的表中数据,对表中数据进行修改审批,这样就能完成对流程的控制.

1.3传统流程开发模式下的优势与弊端

优势:

简单,简介,针对小型的固定流程的项目,我们可以考虑此开发模式

缺点:

1.每一项流程与代码高度耦合,如果我们经常需要修改流程,则需要修改大量的代码.
2.对于复杂流程控制不是很灵活,代码编写难度大.

2.activiti是什么?

2.1常用的流程框架有哪些?

Activiti
JBoss JBPM 6.5
JFlow 6.0
FixFlow 5.0

2.2activiti 的设计逻辑

activiti的设计逻辑其实也是通过数据库表来控制流程,只不过为了解决流程和代码高度耦合,由BPMI这个组织开发了一套流程执行的模板与符号,其实就是花了一张图,只是这张图的底层是以个xml文件,他主要是用来控制流程的.

所以其实activiti就是两部分组成:
第一,bpmn文件(底层是xml文件)画出流程图.
第二,activiti的jar包,解析出bpmn文件,根据bpmn文件来控制流程的执行.

2.3activiti常用名词词汇

流程:即设计的bpmn文件
流程部署:即将bpmn文件存放在数据表中.
流程定义:也就是将bpmn流程文件解析出来的全部东西.
流程实例:也就是流程定义的实例对象,例如,请假流程这是流程定义,张三发起请假,这是流程实例.
任务:当前账号或者员工的任务.
节点:当前流程的一个节点.

2.4常用表分析

activiti会连接数据库生成多张数据库表,根据版本的不同,可能会有23张或者24张或者25张表.这些表存放了全部流程相关的东西
在这里插入图片描述

3.activiti的下载与安装

为什么我们需要下载安装activiti组件呢?其实我们如果流程的bpmn文件不是我们编写的,是由他人写好拷贝给我们的,我们可以不用在eclipse或者idea上安装activiti组件,我们安装的组件其实就是为了画bpmn图而已.

3.1 eclipse下载安装activiti

3.1.1 方式一:在线安装
步骤:
1)help -> Install new Software
在这里插入图片描述
2)然后点击 Add
在这里插入图片描述
3)我们在Name上 写上 Activiti BPMN 2.0 designer
Location上写上 http://activiti.org/designer/update/ (插件更新地址)
在这里插入图片描述
3.1.2方式二:离线安装
步骤:
1)下载离线jar包
在这里插入图片描述
接下来有两种方式:
第一种
在这里插入图片描述
第二种在 help -> Install new Software
在这里插入图片描述
3.1.3验证是否安装成功
查看是否安装成功,在eclipse中,File–>New–>Other–>搜索activiti出现以下界面,安装成功。
在这里插入图片描述

3.2 idea下载安装activiti

3.2.1在线安装
搜索
在这里插入图片描述
安装
在这里插入图片描述
3.2.2 离线安装
步骤:
1)下载actiBPM.jar包,官网下载即可
在这里插入图片描述
2)本地导入插件jar包
在这里插入图片描述
3.2.3验证是否安装成功
右键-new,查看是否可以new bpmn file文件
在这里插入图片描述

4.bpmn的介绍及使用

4.1什么是bpmn?

由BPMI(The Business Process Management Initiative)开发了一套标准叫业务流程建模符号(BPMN - Business Process Modeling Notation)。简单点来说就是用来化流程图,画出的流程图底层是xml文件,可以被解析成一个个的节点.
画图:
在这里插入图片描述
xml文件
在这里插入图片描述

4.2 bpmn文件的作用?

作用:bpmn是用来画流程图的,底层是xml文件,可以被解析成一个个的节点.

4.3bpmn文件包括哪些组件?

开始节点: 流程的开始
结束节点: 流程的结束
任务节点: 中间的任务节点
泳道: 不知
网关: 做接下来的流处理
事件:不知

5.activiti的常用api

activiti的架构图
在这里插入图片描述
5.1 依赖的导入及配置文件的抒写
1).导入依赖

` <dependencies>
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-engine</artifactId>
        <version>7.1.0.M1</version>
    </dependency>
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring</artifactId>
        <version>7.1.0.M1</version>
    </dependency>

    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-bpmn-model</artifactId>
        <version>7.1.0.M1</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.32</version>
    </dependency>
    <!--引入druid数据源 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.12</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>RELEASE</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-nop</artifactId>
        <version>1.7.2</version>
    </dependency>
</dependencies>

2).配置文件的抒写 activiti.cfg.xml

<?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">

    <!--如果用processEngine.getDefaultEngine()方法获取默认的processEngine,则必须文件名为activiti.cfg.xml,并且bean的name也要为这个-->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/actdb1??serverTimezone=GMT%2B8"></property>
        <property name="jdbcUsername" value="root"></property>
        <property name="jdbcPassword" value="root"></property>
        <property name="databaseSchemaUpdate" value="true"></property>
    </bean>
</beans>

5.2 processEngine对象的获取
配置文件:其实就是配置dataSource,配置数据库连接池.因为activiti要操作数据库表
这里是用的mysql数据库.

代码

//方法1 自己加载配置文件
	 	//1.获取configuration对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        //2.获取ProcessEngine对象
        ProcessEngine engine = configuration.buildProcessEngine();

//方法2,默认读取resources/activiti.cfg.xml配置文件
 		//1.得到processEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

5.3 ReposiroryService 对象
主要的方法及功能:
1)部署流程
方法1:classpath部署流程

/**
     * classpath部署流程
     */
    @Test
    public void deploy(){
        //1.获取configuration对象
        ProcessEngineConfiguration configuration = ProcessEngineConfiguration
                .createProcessEngineConfigurationFromResource("activiti.cfg.xml");
        //2.获取ProcessEngine对象
        ProcessEngine engine = configuration.buildProcessEngine();

        //3.部署流程到表中去
        org.activiti.engine.repository.Deployment deployment = engine.getRepositoryService()//部署相关的service
                .createDeployment()  //创建部署对象
                .addClasspathResource("diagrams/helloDemo2.bpmn20.xml")
                .addClasspathResource("diagrams/helloDemo2.bpmn20.png")
                .name("helloDemo2流程")
                .deploy();

        System.out.println("流程部署id:" + deployment.getId());
        System.out.println("流程部署name:" + deployment.getName());

    }

方法2: zip方式部署流程,这里的zip包是bpmn文件和png图片合起来的压缩文件.

 /**
     * zip方式部署流程
     */
    @Test
    public void zipDeploy(){
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();

        //3.部署流程定义diagrams/请假审批.zip
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("diagrams/th5/holiday01.zip");
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);//Charset.forName("GBK")编码问题,必须的加上GBK
        org.activiti.engine.repository.Deployment zipDeployment = engine.getRepositoryService()
                .createDeployment()
                .addZipInputStream(zipInputStream)
                .name("holiday01")
                .deploy();

        System.out.println("流程部署id" + zipDeployment.getId());
        System.out.println("流程部署name" + zipDeployment.getName());

    }

2)查询流程定义

/**
     * 查询流程定义相关信息
     */
    @Test
    public void queryProcessIdentify(){
        //1.得到processEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到repositoryService对象
        org.activiti.engine.RepositoryService repositoryService = processEngine.getRepositoryService();

        //3.查询流程定义
        //3.查询部署的流程定义
        List<ProcessDefinition> list = repositoryService//这是仓库service对象
                .createProcessDefinitionQuery()//这是查询流程定义
                //这是条件,类似于sql语句中where
                .processDefinitionKey("myProcess_1")  //这是通过key查询
                //.processDefinitionId() //这是通过id查询
                //.processDefinitionName() //这是通过那么查询
                //.processDefinitionVersion()// 这是按照版本查询
                //.processDefinitionNameLike()//这是模糊查询

                //这是结果集
                //.singleResult()//这是单个结果
                .list();//这是结果集

        for (ProcessDefinition pd : list) {
            System.out.println(pd.getId());
            System.out.println(pd.getName());
            System.out.println(pd.getVersion());
            System.out.println("-------------");
        }
    }

3)删除流程定义

 /**
     * 删除流程定义相关信息
     */
    @Test
    public void deleteProcessIdentify(){
        //1.得到processEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到repositoryService对象
        org.activiti.engine.RepositoryService repositoryService = processEngine.getRepositoryService();

        //3.删除部署的流程
        //注意:第一个参数1是deployment表的id,true表示强制删除,如果为false表示如果当前流程有未完成的,则不能删除流程部署
        repositoryService.deleteDeployment("1",true);
    }

5.4 RuntimeService 对象
1)启动流程实例

@Test
    public void taskAssigneeUEL(){
        //1.获取processEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.获取runtimeService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();

        //3.准备参数
        //这里的参数一般都是前台传过来的值,获取前台只传了一个值,
        // 我们查询后台数据库表获取后面的几个值,例如填写该单据的经理等
        //这里我们就简化直接运用固定值
        HashMap<String, Object> map = new HashMap<>();
        map.put("assignee1","张三");
        map.put("assignee2","李四");
        map.put("assignee3","王五");
        map.put("assignee4","赵六");
        map.put("money",19999);

         //设置参数方法一
        //4.启动流程实例,并将参数传入实例中
        //参数1:myProcess_1  是流程实例的key值
        //参数2:10001  是关联业务的该记录的主键值
        //参数3:map  是我们传入本流程实例的每个节点的执行者的参数值
        ProcessInstance process1 = runtimeService.startProcessInstanceByKey("holiday01", "1111111", map);

5.5TaskService 对象
作用:查询当前任务,处理任务

/**
     * 这里测试当前的流程变量是否能控制流程,验证成功
     * 完成任务
     */
    @Test
    public void completeTask(){
        //1.获取processEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.测试完成任务
        TaskService taskService = processEngine.getTaskService();

        //3.查询当前名字员工是由有任务
        String name= "赵六";
        Task task = taskService.createTaskQuery()
                .taskAssignee(name)
                .processDefinitionKey("holiday01")
                .singleResult();
        //4.传入holiday.day参数
        holiday holiday = new holiday();
        holiday.setDay(4);
        HashMap<String, Object> map = new HashMap<>();
        map.put("holiday",holiday);

        //设置参数方法三
        //5.验证task是否为空,执行任务,并且传入holiday对象参数,也就是流程中的参数
        if(task != null){
            taskService.complete(task.getId(),map);//完成任务,并传入参数

            //taskService.setVariable("2501","holiday",holiday); //利用task传入参数
            //taskService.setVariableLocal("2501","holiday",holiday); //利用task传入参数,这是设置局部变量,节点变量
            System.out.println(name + "完成任务!!!");
        }else {
            System.out.println(name + "当前没有任务");
        }

5.6HistoryService 对象
作用:查询历史数据.

 /**
     * 历史数据点额查询
     */
    @Test
    public void queryHistory(){
        //1.processEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.获取historyService兑现
        org.activiti.engine.HistoryService historyService = processEngine.getHistoryService();

        //3.创建活动节点实例历史查询器HistoricActivityInstanceQuery
        HistoricActivityInstanceQuery instanceQuery = historyService
                .createHistoricActivityInstanceQuery()
                .processInstanceId("2501");

        //4.获取HistoricActivityInstance历史活动实例对象的集合,并且按照开始时间排序
        List<HistoricActivityInstance> lists = instanceQuery
                //按照开始时间排序
                .orderByHistoricActivityInstanceStartTime().asc().list();

        for (HistoricActivityInstance instance : lists) {
            System.out.println("ActivityId:" + instance.getActivityId());
            System.out.println("ActivityName:" + instance.getActivityName());
            System.out.println("Assignee:" + instance.getAssignee());
            System.out.println("ProcessDefinitionId:" + instance.getProcessDefinitionId());
            System.out.println("ProcessInstanceId:" + instance.getProcessInstanceId());
            System.out.println("=============");
        }
    }

6.流程变量

流程变量是为了让我们在运行流程实例时赋值来控制流程的走势.
1)变量类型
在这里插入图片描述
2)流程变量的作用域
变量作用域
Global 变量 默认的作用域为当前的流程实例.如果在其他节点设置则会覆盖
Local 变量 作用域为当前节点,在其他节点不可用.

3)定义流程变量的格式
第一种: ${变量名}
例如: ${assignee1}
这个表示什么了一个名为assignee1的变量
第二种: ${类名.属性名}
例如: ${holiday.day > 3}
这个表示什么了一个类holiday,他的属性day要大于3

4)常设置流程变量的地方
节点执行人,用于流程实例启动时赋节点任务执行人的值.
在这里插入图片描述
条件变量,用于控制流程的执行
在这里插入图片描述
5)流程变量传值
两种方式
第一种:RuntimeService传值,也就是给整个流程实例传值

 HashMap<String, Object> map = new HashMap<>();
        map.put("assignee1","张三");
        map.put("assignee2","李四");
        map.put("assignee3","王五");
        map.put("assignee4","赵六");

        //设置参数方法一
        //4.启动流程实例,并将参数传入实例中
        //参数1:myProcess_1  是流程实例的key值
        //参数2:10001  是关联业务的该记录的主键值
        //参数3:map  是我们传入本流程实例的每个节点的执行者的参数值
        ProcessInstance process1 = runtimeService.startProcessInstanceByKey("holiday01", "1111111", map);
        
         //设置参数方法二
        //设置一个参数的值
        //参数1  2501  是流程实例id
        //参数2  holiday  是流程变量名
        //参数3  holiday  是变量值
        //runtimeService.setVariable("2501","holiday",holiday);

第二种:TaskService传值,也就是当前节点传值

String name= "赵六";
        Task task = taskService.createTaskQuery()
                .taskAssignee(name)
                .processDefinitionKey("holiday01")
                .singleResult();
        //传入holiday.day参数
        holiday holiday = new holiday();
        holiday.setDay(4);
        HashMap<String, Object> map = new HashMap<>();
        map.put("holiday",holiday);

        //设置参数方法1
        //5.验证task是否为空,执行任务,并且传入holiday对象参数,也就是流程中的参数
        if(task != null){
            taskService.complete(task.getId(),map);//完成任务,并传入参数

            //设置参数方法2
            //taskService.setVariable("2501","holiday",holiday); //利用task传入参数
            //taskService.setVariableLocal("2501","holiday",holiday); //利用task传入参数,这是设置局部变量,节点变量
            System.out.println(name + "完成任务!!!");
        }else {
            System.out.println(name + "当前没有任务");
        }

注意:作为流程变量的类,必须序列化
如果该类不序列化,则会报以下错误.
例如上面什么的holiday类做流程变量;
在这里插入图片描述

7.组任务

应用场景: 就是我们某个节点的处理人不是一个人而是一个职位的人,相当于我们这个节点的处理交给了多个人处理
1)候选人设置:
在这里插入图片描述
候选人处理任务的方式,
由于多个人可以同时处理一个任务,所以需要做并发处理,其实原理就是并发的2pc提交的方式,也就是2阶段提交的方式.

2)处理候选任务的步骤:
在这里插入图片描述
3)具体的代码
候选人拾掇了任务由三种处理方式:
1.归还任务
2.把任务交由其他候选人
3.完成任务

 @Test
    public void CandaditeTask(){
        //1.获取引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.获取taskService对象
        TaskService taskService = processEngine.getTaskService();

        //3.查询当前候选人任务
        String user = "刘备";
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("holiday02")
                .taskCandidateUser(user)
                .singleResult();

        //4.判断是否有任务
        if(task != null) {
			
            //5 确认拾掇任务,参数1为taskid,参数2为当前user
            taskService.claim(task.getId(),user); 
            System.out.println(user + "拾掇任务");
            System.out.println("完成任务");

			//以下三个是多余拾掇的任务的三种处理方式,我们可以任选其一处理任务.
			//6.1 归还组任务
            taskService.setAssignee(task.getId(),null);
            
            //6.2 将当前任务交由其他候选人执行
            String newName = "曹操";
            taskService.addCandidateUser(task.getId(),newName);//添加候选人
            taskService.setAssignee(task.getId(),newName);
            
            //6.3 完成任务
            taskService.complete(task.getId());
        }else {
            System.out.println("当前人物没有候选任务");
        }
    }

8.网关

网关的分类:

1.排他网关(就是接下来的路线只能走一条)
2.并行网关(如果接下来有多条路,必须走所有条路)
3.包含网关(如果接下来有多条路,可以选择其中的多条路)

1)排他网关
应用场景:就是在一个流程中的分支中只能选择一条走,则用排他网关)
注意:接下来如果有多条线路可以走的话,排他网关制定接下来的只能走一条路,就算两条路都为true,他只会选择走一条路,他会选择步骤id更小的流程走.所以如果我们要是有排他网关的话,一定要注意抒写流程id的先后顺序.
具体bpmn图画图如下.
在这里插入图片描述
2)并行网关
应用场景为一个流程需要完成的多项任务,我们需要完成所有的分支任务,但是这些任务不分先后顺序,则我们使用并行网关.
并行网关不会解析条件,也就是并行网关之后的所有完成汇集到一起才算完成.其实有点类似于java并发中的多线程操作中的join方法.如果使用join方法,则两个必须一起结束才能接受下一步的流程.
在这里插入图片描述
3)包含网关
应用场景:我们在一个流程中有多个分支,我们会根据当前实例的参数,选择其中的多个分支执行,不止一个分支,也不是全部的分支必须走,这种我们用包含分支.
在这里插入图片描述
对应执行的包含网关中的分支就是:
在这里插入图片描述

9.Activiti7整个springboot的新特性

1.与springSecurity高度耦合
2.多了两个api.一个是taskRuntime;另一个是processRuntime,这两个接口的实现类高度耦合SpringSecurity.
3.Resource/processes下的bpmn文件会自动部署.
在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值