Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)

Activiti# Activiti5.22整合Springboot

  • 前言
  • 一、Activiti5.22整合Springboot
  • 二、IDEA/Eclipse整合bpmn画图
    • 1.IDEA整合Bpmn
    • 2.Eclipse整合Bpmn
  • 三、利用Eclipse制作会签流程图
    • 3.1流程图命名Id
    • 3.2 任务申请节点配置
    • 3.3 申请节点 添加监听事件
    • 3.4 会签节点配置
    • 3.5 会签监听事件
    • 3.6 配置排他网关
    • 3.7 单人审批节点配置
  • 四、部署流程并测试会签逻辑
    • 4.1流程文件XML准备
    • 4.2 流程部署
    • 4.3 启动实例
    • 4.4 执行任务
  • 五:源码Gitee地址:
  • 总结


前言

此篇文章使用了activiti5.22版本(经典版)来整合Springboot2.3.1.RELEASE,并且介绍了IDEA/Eclipse整合Bpmn制图工具(博主推荐使用Eclipse制图,可后续cp到Idea中),加入会签案例、监听事件、附上源码学习


一、Activiti5.22整合Springboot

1、引入maven包

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- activiti -->
		<dependency>
			<groupId>org.activiti</groupId>
			<artifactId>activiti-spring-boot-starter-basic</artifactId>
			<version>5.22.0</version>
			<exclusions>
				<exclusion>
					<groupId>org.mybatis</groupId>
					<artifactId>mybatis</artifactId>
				</exclusion>
			</exclusions>
		</dependency>


		<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.12</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>

		<!-- mybatis-plus 根据自己需求来 -->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.1.2</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.18</version>
		</dependency>
		
		<!-- hutool工具包 根据自己需求来 -->
		<dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-all</artifactId>
			<version>5.3.7</version>
		</dependency>
	</dependencies>

注意点:注意我用的Springboot版本2.3.1.RELEASE。不清楚的可以直接去下面拉去项目源码

2、Springboot配置文件 application.yml

server:
  port: 8081

spring:
  activiti:
    check-process-definitions: false #自动检查、部署流程定义文件
#    database-schema-update: true #自动更新数据库结构
#    process-definition-location-prefix: classpath:/processes/ #流程定义文件存放目录
  datasource:
#    注意的你数据库版本 我的数据库是8.0 数据库不同  配置会有些不一样  具体请自行搜索
    driver-class-name: com.mysql.cj.jdbc.Driver
#    activit_test是你本地的库名  项目启动会在此库中创建activiti需要的表
    url: jdbc:mysql://localhost:3306/activiti_test?useUnicode=true&characterEncoding=utf8&nullCatalogMeansCurrent=true&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC
    username: root
    password: 199700

#配置mybatis-plus需要指定mapper和entity路径,文件夹需要自己创建
mybatis-plus:
  mapper-locations: classpath:com.aplid.activiti.mapper/*Mapper.xml #指定映射文件
  type-aliases-package: com.aplid.activiti.entity #别名包
  configuration:
    map-underscore-to-camel-case: true #开启驼峰命名
    
#会把activiti操作表的sql打印出来
logging:
  level:
    org.activit.engine.impl.persistence.entity: trace

3、Springboot启动项加注解 2.x以后需要

package com.cn.activiti;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(exclude = {
     
        org.activiti.spring.boot.SecurityAutoConfiguration.class,
        org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
})
public class SpringbootActivitApplication {
     

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

}

4、启动

注意:启动成功以后,打开数据库 在你配置的库下会自动生成25张表
Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第1张图片

二、IDEA/Eclipse整合bpmn画图

1.IDEA整合Bpmn

1.1搜索插件
点击菜单【File】–>【Settings…】打开【Settings】窗口。

点击左侧【Plugins】按钮,在右侧输出"actiBPM",点击下面的【Search in repositories】链接会打开【Browse Repositories】窗口。

进入【Browse Repositories】窗口,选中左侧的【actiBPM】,点击右侧的【Install】按钮,开始安装。
代码如下(示例):

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第2张图片
1.2创建bpmn文件
Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第3张图片

注意:此处博主不推荐使用Idea画流程图,此插件5年没有更新,诸多bug如流程图数据丢失、查找不到监听事件等

2.Eclipse整合Bpmn

流程如下(示例):

2.1 点击Help -> Install New Software,输入以下站点信息:

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第4张图片
2.2 点击 ->Add 添加站点信息

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第5张图片
2.3 添加Bpmn站点信息

Name: Activiti BPMN 2.0 designer
Location: http://activiti.org/designer/update/

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第6张图片

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第7张图片

因为网络的原因,可能会安装不成功,可以上网找插件包自行安装
2.4 创建Bpmn图
Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第8张图片


三、利用Eclipse制作会签流程图

提醒:

新学Activiti的小伙伴要知道,Activiti难的是根据业务制作流程图和编写监听事件。

先放画好的会签流程图,然后再一步一步的解析。

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第9张图片

3.1流程图命名Id

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第10张图片
countersign:会签

Id需要自行设置,部署流程和启动流程实例的时候需要用到。

3.2 任务申请节点配置

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第11张图片
**提示:**Assignee此处是写死由张三进行发起任务,可以使用流程变量进行传入,此处写死,会签节点会使用流程变量示例。

3.3 申请节点 添加监听事件

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第12张图片
注意:依旧是在申请节点配置监听事件。由图可知此监听事件是Complete在申请节点结束后执行,是为了给下一会签节点,传入流程变量(就是会签由哪几个人审批)。

编写监听事件类MyCompeteistener

★★★需继承TaskListener类,重写notify方法。

/**
 * 申请节点结束后指定审批节点的会签审批人
 *
 * @author whr
 * @date 2020/8/5 9:14
 */
public class MyCompeteistener implements TaskListener {
     
	//★★★
	//设置在会签节点审批的人为3人,为A1、A2、A3,而signerList就是流程变量,此字段在会签节点进行设置,下面会讲。
    @Override
    public void notify(DelegateTask arg0) {
     
        List<String> userList = new ArrayList<String>();

        userList.add("A1");

        userList.add("A2");

        userList.add("A3");

        arg0.setVariable("signerList", userList);
    }
}

3.4 会签节点配置

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第13张图片
Assignee要和ElementVariable配置的一样。一个${signer},一个signer
Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第14张图片
${pass}是用户进行会签审批时的结果,通过true还是驳回false,需要获取记录此结果来判断会签率是否通过。

${signerList}则是传入会签人员的流程变量,就是上面申请节点结束后,编写监听事件传入的数据。

Sequential:false 表示会签三人同时能审批任务。true表示按照顺序进行审批。

3.5 会签监听事件

会签这边一共俩个类一个创建节点时执行,一个节点结束执行。

MutiGroupsListener类(创建节点时执行)类型:Create

/**
 *
 *
 * @author whr
 * @date 2020/8/5 9:17
 */
public class MutiGroupsListener implements TaskListener {
     

    @Override
    public void notify(DelegateTask arg0) {
     

        //将通过人数,未通过人数,总数,重新置为0,退回的时候才能重新计算

        arg0.setVariable("passCount", "0");

        arg0.setVariable("totalCount", "0");

        arg0.setVariable("noPassCount", "0");

        //为每一个任务设置处理人

        String signer = (String)arg0.getVariable("signer");

        arg0.setAssignee(signer);

    }

}

JointlySign类 结束执行统计结果 Complete

/**
 * 会签监听器
 *
 * @author whr
 * @date 2020/8/6 10:22
 */
public class JointlySign implements Serializable, TaskListener {
     


    @Override
    public void notify(DelegateTask delegateTask) {
     
        //获取流程id
        String exId = delegateTask.getExecutionId();
        //获取流程参数pass,会签人员完成自己的审批任务时会添加流程参数pass,false为拒绝,true为同意
        ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = engine.getRuntimeService();

        boolean pass = (boolean) runtimeService.getVariable(exId, "pass");
        //流程实例id
        String procInstId = delegateTask.getProcessInstanceId();
        //任务id
        String taskId = delegateTask.getId();
        //variables  流程变量
        Map<String,Object> variables = delegateTask.getVariables();
        
		//调用方法统计
        completeTask1(procInstId,taskId,variables, String.valueOf(pass),delegateTask);

    }

    /**
     * 审批节点有人执行任务时,需要统计执行情况
     * @param procInstId
     * @param taskId
     * @param variables
     * @param passflag
     */

    /* (非 Javadoc)

     * 

Title: completeTask1

*

Description:

* @param procInstId 流程实例id * @param taskId 任务id * @param variables 流程变量 * @param passflag 审批同意标志(yes/no) * @see com.ylkj.base.activiti.service.ActivitiService#completeTask1(java.lang.String, java.lang.String, java.util.Map, java.lang.String) */
public void completeTask1(String procInstId,String taskId, Map<String, Object> variables,String passflag,DelegateTask delegateTask) { //获取当前节点的task_def_key_,此段代码主要用于区分多个节点时,审批通过记录数与总数 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); Task taskQuery = processEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult(); List<Task> tasks = processEngine.getTaskService().createTaskQuery().taskName(taskQuery.getName()).processInstanceId(procInstId).list(); int passCount = 0;//审批同意人数 int noPassCount = 0;//审批不同意人数 int totalCount = 0;//任务总人数 //当前的执行情况 String tmpPassCount = processEngine.getRuntimeService().getVariable(procInstId, taskQuery.getTaskDefinitionKey()+"#passCount")+""; String tmpNoPassCount = processEngine.getRuntimeService().getVariable(procInstId, taskQuery.getTaskDefinitionKey()+"#noPassCount")+""; String tmpTotal = processEngine.getRuntimeService().getVariable(procInstId, taskQuery.getTaskDefinitionKey()+"#totalCount")+""; if(!tmpPassCount.equals("null") && !tmpPassCount.trim().equals("")){ passCount = Integer.parseInt(tmpPassCount); } if(!tmpNoPassCount.equals("null") && !tmpNoPassCount.trim().equals("")){ noPassCount = Integer.parseInt(tmpNoPassCount); } if(tmpTotal.equals("null") || tmpTotal.trim().equals("")){ totalCount = tasks.size(); } else if(!tmpTotal.equals("null") && !tmpTotal.trim().equals("")){ totalCount = Integer.parseInt(tmpTotal); } for (Task tmp:tasks) { if(passflag.equals("true") && tmp.getId().equals(taskId)){ //选择通过则通过人数+1 passCount++; } if(passflag.equals("false") && tmp.getId().equals(taskId)){ //选择不通过则不通过人数+1 noPassCount++; } } //变量回写记录 variables.put("passCount", passCount); variables.put("noPassCount", noPassCount); variables.put("totalCount", totalCount); variables.put(taskQuery.getTaskDefinitionKey()+"#passCount", passCount); variables.put(taskQuery.getTaskDefinitionKey()+"#noPassCount", noPassCount); variables.put(taskQuery.getTaskDefinitionKey()+"#totalCount", totalCount); // ProcessEngine engine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = processEngine.getRuntimeService(); runtimeService.setVariable(delegateTask.getExecutionId(), "passCount", passCount); runtimeService.setVariable(delegateTask.getExecutionId(), "noPassCount", noPassCount); runtimeService.setVariable(delegateTask.getExecutionId(), "totalCount", totalCount); runtimeService.setVariable(delegateTask.getExecutionId(), taskQuery.getTaskDefinitionKey()+"#passCount", passCount); runtimeService.setVariable(delegateTask.getExecutionId(), taskQuery.getTaskDefinitionKey()+"#noPassCount",noPassCount); runtimeService.setVariable(delegateTask.getExecutionId(), taskQuery.getTaskDefinitionKey()+"#totalCount", totalCount); // processEngine.getTaskService().complete(taskId,variables); } }

绑定监听事件
Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第15张图片

3.6 配置排他网关

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第16张图片

可以看到图中一个大X的图标就是排他网关,流程走到此处会进行会签率判断是驳回,还是继续往下走。

配置驳回线路
Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第17张图片

配置通过条件

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第18张图片
可以看到此处的通过率设置的为1/3,通过则流程继续,驳回则回到申请节点处,张三重新申请。

3.7 单人审批节点配置

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第19张图片
会签结束后,再来个单人审批节点,此处的审批人也是写死。

四、部署流程并测试会签逻辑

说明:

至此我们的流程图和监听事件都完成并配置好。将此流程图复制到Idea中进行部署,博主测试过程中碰见数据丢失问题,建议转成xml文件进行部署。

4.1流程文件XML准备

在Eclipse中右键将bpmn图使用XML打开,操作如下:
Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第20张图片

转化成XML后复制移动到Idea中,需要记得更改监听事件的位置。
将此XML内容复制到Idea中,记得将文件名称改为*.bpmn20.xml,便于部署
在resources文件下创建bpmn文件夹,移动过来的流程XML文件放于此文件夹下,方便读取。

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第21张图片

4.2 流程部署

创建部署类DeploymentProcess

/**
 * 部署流程
 *
 * @author whr
 * @date 2020/8/4 13:32
 */
public class DeploymentProcess {
     

    public static void main(String[] args) {
     
        startProcess();
    }

    /**
     * 部署流程
     */
    private static void startProcess() {
     
        //创建ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //得到RepositoryService实例
        RepositoryService repositoryService = processEngine.getRepositoryService();

        DeploymentBuilder deployment = repositoryService.createDeployment(); 
        //创建一个发布对象
        deployment.addClasspathResource("bpmn/process_1.bpmn20.xml");  
        //添加流程文件路径
        deployment.name("会签流程"); 
        //添加流程部署名称
        deployment.category("会签分类");

        Deployment deploy = deployment.deploy();

    }
}

添加配置activiti.cfg.xml文件,放入resources文件夹下,数据库需配置开始生成25张表的库。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/contex http://www.springframework.org/schema/context/spring-context.xsd
						http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--配置数据源,dbcp-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/activiti_test?useUnicode=true&characterEncoding=utf8&nullCatalogMeansCurrent=true&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC" />
        <property name="username" value="root" />
        <property name="password" value="199700" />
    </bean>

    <!--activiti单独运行的processEngine配置,获取processEngineConfiguration对象-->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"></property>
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>
    
</beans>

运行main方法查看数据库:

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第22张图片

4.3 启动实例

编写启动类StartInstance

/**
 * 启动实例
 *
 * @author whr
 * @date 2020/8/4 14:09
 */
public class StartInstance {
     

    public static void main(String[] args) {
     
        startInstance();
    }


    /**
     * 启动流程实例
     */
    private static void startInstance() {
     
        //得到ProcessEnginge对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //得到RunService对象
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //创建流程实例  流程定义的key: bpmn id
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("countersign");


        //输出相关信息
        System.out.println("流程部署id" + processInstance.getDeploymentId());
        System.out.println("流程定义id" + processInstance.getProcessDefinitionId());
        System.out.println("流程实例id" + processInstance.getId());
        System.out.println("活动id" + processInstance.getActivityId());
    }



}

注意:一开始流程图让你定义的Id就是在此时用到,启动流程实例一定依旧流程启动,这个Id就是这个流程的Key 例如代码中的“countersign”。

执行main方法查看数据库

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第23张图片

启动实例 实际就意味着一条任务开始。

4.4 执行任务

编写执行类CarryTask

/**
 * 执行任务
 *
 * @author whr
 * @date 2020/8/17 11:08
 */
public class CarryTask {
     

    public static void main(String[] args) {
     
        activitiCompleteTask();
    }

    private static void activitiCompleteTask() {
     
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到TaskService对象
        TaskService taskService = processEngine.getTaskService();

        //3.查询当前用户的任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("countersign")
                .taskAssignee("张三")
                .singleResult();

        //4.处理任务,结合当前用户任务列表的查询操作的话,任务ID:task.getId()
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("pass", true);

        MutiGroupsListener mutiGroupsListener = new MutiGroupsListener();

        taskService.complete(task.getId(), variables);

        //5.输出任务的id
        System.out.println(task.getId());

    }
}

可以看到启动流程实例以后,数据库任务表中显示张三执行申请任务,而这和我们一开始配置流程图正好匹配,所以上图代码taskAssignee(“张三”),张三执行。

执行main方法查看数据库。

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第24张图片
可以看到此时变成A1、A2、A3同时审批任务。
更改执行任务的代码,将执行人更改为A1,传入审批结果为false。
代码如下:

/**
 * 执行任务
 *
 * @author whr
 * @date 2020/8/17 11:08
 */
public class CarryTask {
     

    public static void main(String[] args) {
     
        activitiCompleteTask();
    }

    private static void activitiCompleteTask() {
     
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到TaskService对象
        TaskService taskService = processEngine.getTaskService();

        //3.查询当前用户的任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("countersign")
                //此处更改任务执行人
                .taskAssignee("A1")
                .singleResult();

        //4.处理任务,结合当前用户任务列表的查询操作的话,任务ID:task.getId()
        Map<String, Object> variables = new HashMap<String, Object>();
        //此处更改审批结果
        variables.put("pass", false);

        MutiGroupsListener mutiGroupsListener = new MutiGroupsListener();

        taskService.complete(task.getId(), variables);

        //5.输出任务的id
        System.out.println(task.getId());

    }
}

执行main方法查看数据库。

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第25张图片
可得:A1执行完任务,并且是没有同意,通过率没有到大1/3。

继续A2执行main方法,A2同意此任务。

/**
 * 执行任务
 *
 * @author whr
 * @date 2020/8/17 11:08
 */
public class CarryTask {
     

    public static void main(String[] args) {
     
        activitiCompleteTask();
    }

    private static void activitiCompleteTask() {
     
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //2.得到TaskService对象
        TaskService taskService = processEngine.getTaskService();

        //3.查询当前用户的任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("countersign")
                .taskAssignee("A2")
                .singleResult();

        //4.处理任务,结合当前用户任务列表的查询操作的话,任务ID:task.getId()
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("pass", true);

        MutiGroupsListener mutiGroupsListener = new MutiGroupsListener();

        taskService.complete(task.getId(), variables);

        //5.输出任务的id
        System.out.println(task.getId());

    }
}

Activiti5.22整合Springboot(画图详解,会签监听事件,附带源码)_第26张图片
A2执行完,任务已经通过,通过率大于1/3,所以任务向下一节点走,到王五单人审批。可见会签逻辑已成功。

五:源码Gitee地址:

点击获取

总结

Activiti整合Springboot:
以上就是今天要讲的内容,本文仅仅简单介绍了会签流程的案例,而Activiti提供了大量能使我们快速便捷地处理数据的函数和方法。
本人小白文章中也有一些代码是学习时借鉴网上的代码,在里面修改,有什么不对的地方欢迎指正。

你可能感兴趣的:(java,activiti,spring,boot,spring,数据库)