Activiti学习记录(一)

系列文章目录


前言

学习activiti记录过程中的一些问题。
springBoot 版本 2.5.2
activiti版本 7.1.0.M6

一、Demo

1.1 项目整体架构

因为这是一个学习记录的过程,所以可能会有多个demo,项目结构如下:在这里插入图片描述

1.2 父工程

1.2.1 POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>org.chzu</groupId>
    <artifactId>activiti</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>activiti_example_01</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <!-- 各个依赖的版本号 -->
        <activiti.version>7.1.0.M6</activiti.version>
        <mysql.version>8.0.18</mysql.version>
        <jaskson-datebind.version>2.10.2</jaskson-datebind.version>
        <!-- 设置编码为UTF-8 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencyManagement>
        <dependencies>

            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-spring-boot-starter</artifactId>
                <version>${activiti.version}</version>
            </dependency>

            <dependency>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>${jaskson-datebind.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

1.3 子工程(activiti_example_01)

1.3.1 POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>activiti</artifactId>
        <groupId>org.chzu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>activiti_example_01</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <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>
        </dependency>

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

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

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

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

    </dependencies>

</project>

1.3.2 YML

spring:
  ##数据库连接信息
  datasource:
    # 数据源配置
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/activiti?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
    username: root
    password: root

  activiti:
      #1.false:默认值,activiti启动时,对比数据库表中保存的版本,如果不匹配。将抛出异常
      #2.true:启动时会对数据库中所有表进行更新操作,如果表存在,不做处理,反之,自动创建表
      #3.create_drop:启动时自动创建表,关闭时自动删除表
      #4.drop_create:启动时,删除旧表,再创建新表
    database-schema-update: true
      #activiti7默认不生成历史信息表,需手动设置开启
    db-history-used: true
    #full:保存历史数据的最高级别,可保存全部流程相关细节,包括流程流转各节点参数
    history-level: full
    #自动部署验证设置:true-开启(默认)、false-关闭
    check-process-definitions: true
    process-definition-location-prefix: classpath:/processes/
    process-definition-location-suffixes:
      - "**.png"
      - "**.bpmn20.xml"

1、配置数据库信息
2、配置activiti
check-process-definitions
process-definition-location-prefix是指定activiti流程描述文件的即路径,启动时,activiti就会去寻找此路径下的流程描述文件,并且自动部署;
process-definition-location-suffixes是一个String数组,表示描述文件的默认后缀名;
默认配置如下:

@ConfigurationProperties("spring.activiti")
class ActivitiProperties
	......
    public ActivitiProperties() {
        this.historyLevel = HistoryLevel.NONE;
        this.processDefinitionLocationPrefix = "classpath*:**/processes/";
        this.processDefinitionLocationSuffixes = Arrays.asList("**.bpmn20.xml", "**.bpmn");
        this.useStrongUuids = true;
        this.copyVariablesToLocalForTasks = true;
        this.deploymentMode = "default";
        this.serializePOJOsInVariablesToJson = true;
        this.javaClassFieldForJackson = Id.CLASS.getDefaultPropertyName();
    }

也可以使用手动部署

1.3.3 创建流程定义文件

2020版idea搜索bpmn插件,结果如图所示:
在这里插入图片描述
我下载了如图的两个插件。
resources文件夹下创建processes文件夹(如果没有此文件夹,启动会报错,大致是找不到processes文件夹),在processes文件夹下创建如图所示文件:
在这里插入图片描述
点击如下图所示的Designer,就可以定义了,连线直接点击想要连接的两个图标就行了。
在这里插入图片描述
在这里插入图片描述但是使用这个插件遇到的(有可能是我自己的问题):
1、只有第一次拖拽的时候可以移动位置,确定后无法调整
2、没法在图标上直接修改名称(上图中文是在xml文件中修改)
3、它这里的Task只有Service Task一个选项(上图也是在xml中将Service Task 修改为User Task 的)

右键选择如图所示,将其保存为png图片,其实也可以在Designer保存,但是Designer无法调整图标位置
在这里插入图片描述在这里插入图片描述

1.3.4 完整的的xml文件

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema" 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"
             typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath"
             targetNamespace="http://www.activiti.org/processdef">
    <process id="holiday" name="holiday" isExecutable="true">
        <endEvent id="EndEvent_1" name="End Event 1"/>
        <sequenceFlow sourceRef="StartEvent_1" targetRef="ServiceTask_1" id="StartEvent_1-ServiceTask_1"/>
        <sequenceFlow sourceRef="ServiceTask_1" targetRef="ServiceTask_2" id="ServiceTask_1-ServiceTask_2"/>
        <sequenceFlow sourceRef="ServiceTask_2" targetRef="EndEvent_1" id="ServiceTask_2-EndEvent_1"/>
        <userTask id="ServiceTask_1" name="填写请假申请单" activiti:assignee="zhangsan"/>
        <userTask id="ServiceTask_2" name="管理员审批" activiti:assignee="lisi"/>
        <startEvent id="StartEvent_1" name="Start Event 1"/>
    </process>
    <bpmndi:BPMNDiagram id="BPMNDiagram_holiday">
        <bpmndi:BPMNPlane bpmnElement="holiday" id="BPMNPlane_holiday">
            <bpmndi:BPMNShape bpmnElement="StartEvent_1">
                <omgdc:Bounds height="48.0" width="48.0" x="619.0" y="96.0"/>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="ServiceTask_1">
                <omgdc:Bounds height="48.0" width="120.0" x="655.0" y="225.0"/>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="ServiceTask_2">
                <omgdc:Bounds height="48.0" width="120.0" x="631.0" y="360.0"/>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="EndEvent_1">
                <omgdc:Bounds height="48.0" width="48.0" x="667.0" y="454.0"/>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNEdge bpmnElement="StartEvent_1-ServiceTask_1">
                <omgdi:waypoint x="643.0" y="120.0"/>
                <omgdi:waypoint x="715.0" y="249.0"/>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="ServiceTask_1-ServiceTask_2">
                <omgdi:waypoint x="715.0" y="249.0"/>
                <omgdi:waypoint x="691.0" y="384.0"/>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="ServiceTask_2-EndEvent_1">
                <omgdi:waypoint x="691.0" y="384.0"/>
                <omgdi:waypoint x="691.0" y="478.0"/>
            </bpmndi:BPMNEdge>
        </bpmndi:BPMNPlane>
    </bpmndi:BPMNDiagram>
</definitions>

二、测试

可以设置日志的级别为DEBUG,这样可以在运行栏中看到操作了哪些数据库表
创建一个测试类

@SpringBootTest(classes = Example01.class)
public class ActivitiTest {

    @Autowired
    private SecurityUtil securityUtil;

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    TaskService taskService;
}

2.1 手动部署流程

    @Test
    public void deploy(){
        //定义流程名称,并把bpmn与png文件部署到数据库
        DeploymentBuilder builder = repositoryService.createDeployment();
        Deployment deployment = builder
                .name("请假申请流程")
                .addClasspathResource("processes/holiday.bpmn20.xml")
                .addClasspathResource("processes/holiday.bpmn20.png")
                .deploy();
        //输出部署信息
        System.out.println("流程ID"+deployment.getId());
        System.out.println("流程名称"+deployment.getName());
        System.out.println("流程部署时间"+deployment.getDeploymentTime());
    }

如果你的配置文件中设置了自动部署,在这里又手动部署的话,其实是没什么影响的,数据库中的记录有一个VERSION字段,是用来区别的同一个流程文件版本的。
在这里插入图片描述
当存在多个流程文件时也可以将流程文件打包部署

        InputStream in = this.getClass().getClassLoader().getResourceAsStream("processes/holiday.zip");
        ZipInputStream stream = new ZipInputStream(in);
        Deployment deploy = repositoryService.createDeployment()
                .addZipInputStream(stream)
                .deploy();

2.2 启动流程实例

        //启动流程实例,根据流程的id holiday 获取流程实例
        //<process id="holiday" name="请假流程" isExecutable="true">
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("holiday");

        String id = instance.getId();
        String name = instance.getName();
        Map<String, Object> variables = instance.getProcessVariables();
        String businessKey = instance.getBusinessKey();
        String definitionId = instance.getProcessDefinitionId();
        String activityId = instance.getActivityId();

		//可以输出一些信息
		System.out.println("流程定义的ID :"+definitionId);
		System.out.println("name"+name);

2.3 查询个人任务

        //参与者查询自己的任务
        //根据key和任务负责人查询任务,返回一个Task列表
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey("holiday")
                .taskAssignee("zhangsan")
                .list();
        //输出
        for (Task task : list) {
            log.info(task.getId());
            log.info(task.getName());
        }

2.4 查询和完成任务

        //参与者查询自己的任务,这里singleResult()返回一个Task实例
        Task task1 = taskService.createTaskQuery()
                .processDefinitionKey("holiday")
                .taskAssignee("lisi")
                .singleResult();

        //完成任务
        taskService.complete(task1.getId());

2.5 下载流程定义文件

 		//查询流程的定义信息
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("holiday")
                .singleResult();
        //通过流程定义信息,获取部署ID
        String deploymentId = definition.getDeploymentId();

        //通过部署ID读取资源
        String resourceName = definition.getResourceName();
        InputStream stream1 = repositoryService.getResourceAsStream(deploymentId, resourceName);

        File file1 = new File("1.bpmn");
        FileOutputStream out1 = new FileOutputStream(file1);

        byte[] bytes = new byte[1024];
        BufferedInputStream bis1 = new BufferedInputStream(stream1);
        BufferedOutputStream bos1 = new BufferedOutputStream(out1);

        while ((len = bis1.read(bytes)) != -1){
            bos1.write(bytes,0,len);
        }

        bis1.close();
        bos1.close();

2.6 流程的删除

//删除流程时若流程已经启动则删除实例会报错
repositoryService.deleteDeployment("ac9105ee-1848-11ec-a8c9-005056c00001");

//即使流程已经启动,也会删除
//repositoryService.deleteDeployment("ac9105ee-1848-11ec-a8c9-005056c00001",true);

三、总结

3.1 springboot对Activiti自动配置

ProcessEngineAutoConfiguration 注册一个springProcessEngineConfiguration组件

public class ProcessEngineAutoConfiguration extends AbstractProcessEngineAutoConfiguration{
	@Bean
    @ConditionalOnMissingBean
    public SpringProcessEngineConfiguration springProcessEngineConfiguration(....){
		
	}
}

SpringProcessEngineConfiguration 继承了ProcessEngineConfigurationImpl 并重写了(调用了父类的方法)buildProcessEngine()方法,这个方法返回一个ProcessEngine,它是activiti流程引擎核心类。

public class SpringProcessEngineConfiguration extends ProcessEngineConfigurationImpl implements ApplicationContextAware {
	......
  @Override
  public ProcessEngine buildProcessEngine() {
    ProcessEngine processEngine = super.buildProcessEngine();
    ProcessEngines.setInitialized(true);
    autoDeployResources(processEngine);
    return processEngine;
  }
  ......

ProcessEngineConfigurationImpl 的buildProcessEngine()方法,这个方法中调用的init()方法初始化很多的资源,比如其中的xxxxService。

public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfiguration {
		.....
		protected RepositoryService repositoryService = new RepositoryServiceImpl();
		protected RuntimeService runtimeService = new RuntimeServiceImpl();
		protected HistoryService historyService = new HistoryServiceImpl(this);
		protected TaskService taskService = new TaskServiceImpl(this);
		protected ManagementService managementService = new ManagementServiceImpl();
	   ......
	    public ProcessEngine buildProcessEngine() {
        	this.init();
        	ProcessEngineImpl processEngine = new ProcessEngineImpl(this);
        	this.postProcessEngineInitialisation();
        	return processEngine;
    }
		public void init() {
			.....
			initServices
			.....
		}
		public void initServices() {
    i		nitService(repositoryService);
    		initService(runtimeService);
    		initService(historyService);
    		initService(taskService);
    		initService(managementService);
    		initService(dynamicBpmnService);
  }
  
}

3.2 遇到的问题

在下载上传的流程定义png资源的时候,在数据库的act_re_procdef表中【DGRM_RESOURCE_NAME_】为png流程图片名称。在我上传流程定义资源之后表act_ge_bytearray中存在png文件,但是在act_re_procdef中【DGRM_RESOURCE_NAME_】为null。
我没有找到原因,希望有知道原因的同学告知一下

问题解决:发现是自己的图片保存的名称是holiday.bpmn20.png,名称后缀一定要是**.png才行,修改名称为holiday.png**,就可以了

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值