欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Activiti6.0学习实践(3)-应用工程(helloworld)构建

程序员文章站 2024-03-06 10:36:19
...

本章主要是通过构建一个流程应用,来了解通过idea来创建流程图和编写代码来创建一个流程应用。

目录

1、IDEA安装插件actiBPM

2、创建一个maven工程

3、创建BPMN流程图

3.1 创建一个BPMN 流程

3.2 修改元素的名称

4、BPMN定义文件xml化

​​​​​​​5、修改pom文件添加依赖

​​​​​​​6、创建应用入口DemoMain类

7、测试验证

8、问题处理小结

8.1、Idea工程报错, write-unsafe

​​​​​​​8.2、流程定义获取name乱码


​​​​​​​

1、IDEA安装插件actiBPM

启动idea,通过 File-setting 找到 plugins项目

Activiti6.0学习实践(3)-应用工程(helloworld)构建

点击安装,安装完成后根据提示重启IDEA。

2、创建一个maven工程

接下来,我们需要创建一个新的maven工程

Activiti6.0学习实践(3)-应用工程(helloworld)构建

 

Activiti6.0学习实践(3)-应用工程(helloworld)构建

 

 

Activiti6.0学习实践(3)-应用工程(helloworld)构建

 

3、创建BPMN流程图

下面我们通过这个工程创建一个二级审批流程

Activiti6.0学习实践(3)-应用工程(helloworld)构建

​​​​​​​3.1 创建一个BPMN 流程

Activiti6.0学习实践(3)-应用工程(helloworld)构建

下面我们就可以在这个界面上画流程图了(话说这个界面槽点多多)

我们要画的流程是一个二级审批流程:

开始--员工填写请假流程--部门主管审批—人力审批—结束

Activiti6.0学习实践(3)-应用工程(helloworld)构建

​​​​​​​3.2 修改元素的名称

对每个元素进行修改名称,修改后的内容如下图所示

Activiti6.0学习实践(3)-应用工程(helloworld)构建

设定属性: form Property中的 id, name, type

Activiti6.0学习实践(3)-应用工程(helloworld)构建

注意上图中的类型后面实践中证明是错误的,只要都用小写就好,否则会报错误。(string, date等)

好,流程的配置到这里,暂时先放一下,我们回到工程​​​​​​​

4、BPMN定义文件xml化

将我们设计的BPMN定义文件,复制,复制的时候重命名,通常是在后面增加20.xml。 20表示遵循BPMN2.0规范,重命名后,可以直接打开xml查看,和我们熟知的xml文档没有什么差别。

Activiti6.0学习实践(3)-应用工程(helloworld)构建

下面是本例中xml内容:

<?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="m1576563040688" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="myProcess_1" isClosed="false" isExecutable="true" name="二级审批流程" processType="None">
    <startEvent id="_2" name="开始"/>
    <userTask activiti:exclusive="true" id="_3" name="员工填写">
      <extensionElements>
        <activiti:formProperty id="f1" name="员工姓名" type="string"/>
        <activiti:formProperty id="f2" name="申请内容" type="string"/>
        <activiti:formProperty id="f3" name="提交时间" type="date"/>
      </extensionElements>
    </userTask>
    <sequenceFlow id="_4" sourceRef="_2" targetRef="_3"/>
    <exclusiveGateway gatewayDirection="Unspecified" id="_5" name="提交or取消"/>
    <userTask activiti:exclusive="true" id="_6" name="主管审批">
      <extensionElements>
        <activiti:formProperty id="f4" name="审批人姓名" type="string"/>
        <activiti:formProperty id="f5" name="审批内容" type="string"/>
        <activiti:formProperty id="f6" name="审批时间" type="date"/>
      </extensionElements>
      ‘
    </userTask>
    <sequenceFlow id="_7" sourceRef="_3" targetRef="_5"/>
    <sequenceFlow id="_8" sourceRef="_5" targetRef="_6"/>
    <userTask activiti:exclusive="true" id="_11" name="人力审批">
      <extensionElements>
        <activiti:formProperty id="f7" name="人力姓名" type="string"/>
        <activiti:formProperty id="f8" name="审批内容" type="string"/>
        <activiti:formProperty id="f9" name="审批时间" type="date"/>
      </extensionElements>
    </userTask>
    <exclusiveGateway gatewayDirection="Unspecified" id="_12" name="主管审批校验"/>
    <exclusiveGateway gatewayDirection="Unspecified" id="_13" name="人力审批校验"/>
    <endEvent id="_14" name="结束"/>
    <sequenceFlow id="_15" sourceRef="_6" targetRef="_12"/>
    <sequenceFlow id="_16" sourceRef="_12" targetRef="_11"/>
    <sequenceFlow id="_17" sourceRef="_11" targetRef="_13"/>
    <sequenceFlow id="_18" sourceRef="_13" targetRef="_14"/>
    <sequenceFlow id="_19" sourceRef="_12" targetRef="_3"/>
    <sequenceFlow id="_9" sourceRef="_13" targetRef="_3"/>
    <sequenceFlow id="_10" sourceRef="_5" targetRef="_14"/>
  </process>
  <bpmndi:BPMNDiagram documentation="background=#3C3F41;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="myProcess_1">
      <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
        <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="185.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="105.0" y="175.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" isMarkerVisible="false">
        <omgdc:Bounds height="32.0" width="32.0" x="270.0" y="180.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.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="175.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_11" id="Shape-_11">
        <omgdc:Bounds height="55.0" width="85.0" x="580.0" y="175.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="500.0" y="190.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_13" id="Shape-_13" isMarkerVisible="false">
        <omgdc:Bounds height="32.0" width="32.0" x="750.0" y="180.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_14" id="Shape-_14">
        <omgdc:Bounds height="32.0" width="32.0" x="840.0" y="185.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_15" id="BPMNEdge__15" sourceElement="_6" targetElement="_12">
        <omgdi:waypoint x="435.0" y="202.5"/>
        <omgdi:waypoint x="500.0" y="206.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="_11" targetElement="_13">
        <omgdi:waypoint x="665.0" y="202.5"/>
        <omgdi:waypoint x="750.0" y="196.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="_12" targetElement="_11">
        <omgdi:waypoint x="532.0" y="206.0"/>
        <omgdi:waypoint x="580.0" y="202.5"/>
        <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="_3">
        <omgdi:waypoint x="516.0" y="190.0"/>
        <omgdi:waypoint x="368.0" y="125.0"/>
        <omgdi:waypoint x="147.5" y="175.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_18" id="BPMNEdge__18" sourceElement="_13" targetElement="_14">
        <omgdi:waypoint x="782.0" y="196.0"/>
        <omgdi:waypoint x="840.0" y="201.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="32.0" y="201.0"/>
        <omgdi:waypoint x="105.0" y="202.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7" sourceElement="_3" targetElement="_5">
        <omgdi:waypoint x="190.0" y="202.5"/>
        <omgdi:waypoint x="270.0" y="196.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="_6">
        <omgdi:waypoint x="302.0" y="196.0"/>
        <omgdi:waypoint x="350.0" y="202.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_13" targetElement="_3">
        <omgdi:waypoint x="766.0" y="180.0"/>
        <omgdi:waypoint x="470.0" y="100.0"/>
        <omgdi:waypoint x="147.5" y="175.0"/>
        <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="_5" targetElement="_14">
        <omgdi:waypoint x="286.0" y="212.0"/>
        <omgdi:waypoint x="530.0" y="295.0"/>
        <omgdi:waypoint x="856.0" y="217.0"/>
        <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>

​​​​​​​5、修改pom文件添加依赖

在pom文件中,添加我们这工程的依赖,具体见如下pom.xml文件

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

    <groupId>com.study.myactiviti</groupId>
    <artifactId>myactiviti-app</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-engine</artifactId>
            <version>6.0.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>25.0-jre</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>
    </dependencies>

</project>

​​​​​​​6、创建应用入口DemoMain类

在入口类中,我们要实现整个流程引擎应用的串联。因此应用需要如下几个步骤

  1. 创建流程引擎

Activiti6.0学习实践(3)-应用工程(helloworld)构建

    2. 部署流程定义文件xml

Activiti6.0学习实践(3)-应用工程(helloworld)构建    3、启动流程

Activiti6.0学习实践(3)-应用工程(helloworld)构建

   4、处理流程

Activiti6.0学习实践(3)-应用工程(helloworld)构建

这一步主要是获取任务列表,并获取任务中的表单属性,对表单属性进行处理。上面代码中引入了scanner进行命令式交互。

完成代码见下面:

package com.study.activiti;

import com.google.common.collect.Maps;
import org.activiti.engine.*;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.impl.form.DateFormType;
import org.activiti.engine.impl.form.StringFormType;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;

/**
 * Describe:启动类
 *
 * @author cwqsolo
 * @date 2019/12/17
 */
public class DemoMain {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoMain.class);

    public static void main(String[] args) throws ParseException {
        LOGGER.info("启动应用------>>>");

        //步骤1--创建流程引擎
        ProcessEngine processEngine = getProcessEngine();

        //步骤2---部署流程定义
        ProcessDefinition processDefinition = getProcessDefinition(processEngine);

        //步骤3--启动流程
        ProcessInstance processInstance = getProcessInstance(processEngine, processDefinition);
        LOGGER.info("启动流程实例 {}", processInstance.getProcessDefinitionKey());

        //步骤4--处理流程任务
        Scanner scanner = new Scanner(System.in);
        while (processInstance != null && !processInstance.isEnded()) {
            TaskService taskService = processEngine.getTaskService();
            List<Task> list = taskService.createTaskQuery().list();
            LOGGER.info("待处理任务数量 {}", list.size());

            for (Task task : list) {
                LOGGER.info("待处理任务 {}", task.getName());
                FormService formService = processEngine.getFormService();
                TaskFormData taskFormData = formService.getTaskFormData(task.getId());
                List<FormProperty> formProperties = taskFormData.getFormProperties();
                HashMap<String, Object> objectObjectHashMap = Maps.newHashMap();
                //从流程中获取表单,并存入到hashmap
                for (FormProperty formProperty : formProperties) {
                    String s = null;
                    if (StringFormType.class.isInstance(formProperty.getType())) {
                        LOGGER.info("请输入 {} ?", formProperty.getName());
                        s = scanner.nextLine();
                        objectObjectHashMap.put(formProperty.getId(), s);
                    } else if (DateFormType.class.isInstance(formProperty.getType())) {
                        LOGGER.info("请输入 {} ? 格式 ( yyyy-MM-dd)", formProperty.getName());
                        s = scanner.nextLine();
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                        Date parse = simpleDateFormat.parse(s);
                        objectObjectHashMap.put(formProperty.getId(), parse);
                    } else {
                        LOGGER.info("类型暂时不支持 {} ", formProperty.getType());
                    }
                    LOGGER.info("您输入的内容是 [{}] ", s);

                    LOGGER.info("请输入 {} ?", formProperty.getName());
                }
                //提交表单
                taskService.complete(task.getId(), objectObjectHashMap);
                //获取流程最新的状态
                processInstance = processEngine.getRuntimeService()
                        .createProcessInstanceQuery()
                        .processInstanceId(processInstance.getId())
                        .singleResult();

            }


        }


        LOGGER.info("------>>>结束应用");

    }

    private static ProcessInstance getProcessInstance(ProcessEngine processEngine, ProcessDefinition processDefinition) {
        //获取流程引擎的一个运行时服务
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //根据id启动流程实例, 启动流程实例的方法有多种,上面获取了id,可以采用这个方法
        return runtimeService.startProcessInstanceById(processDefinition.getId());

    }

    /**
     * 部署流程定义
     * @param processEngine
     * @return
     */
    private static ProcessDefinition getProcessDefinition(ProcessEngine processEngine) {
        //由流程引擎创建一个流程库服务对象
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //流程库服务对象创建一个流程部署构建对象
        DeploymentBuilder deployment = repositoryService.createDeployment();
        //流程构建对象加载配置文件
        deployment.addClasspathResource("./comm2Level.bpmn20.xml");
        //创建指定流程配置的部署对象并获取部署ID
        Deployment deploy = deployment.deploy();
        String id = deploy.getId();

        //根据流程库服务对象获取流程定义对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(id).singleResult();
        LOGGER.info("流程定义文件 {}, 流程ID {}", processDefinition.getName(), processDefinition.getId());
        return processDefinition;
    }

    /**
     * 创建流程引擎
     * @return
     */
    private static ProcessEngine getProcessEngine() {
        //流程引擎的创建有多种方法,本例中使用mysql,因此需要从数据源来创建, 数据源定义在activiti.cfg.xml 文件中
        ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault();
        LOGGER.info("configuration = {}", cfg);
        //获取引擎
        ProcessEngine processEngine = cfg.buildProcessEngine();
        String name = processEngine.getName();
        String version = ProcessEngine.VERSION;
        LOGGER.info("获取流程引擎 {}, 版本为{}", name, version);
        return processEngine;
    }
}

7、测试验证

下面将我们的demo应用跑起来,则会一步一步进行任务处理,在每个任务界面进行表单内容的输入

​​​​​​​Activiti6.0学习实践(3)-应用工程(helloworld)构建

 

8、问题处理小结

8.1、Idea工程报错, write-unsafe

问题描述:系统报write-unsafe错误,不过不影响工程。

Activiti6.0学习实践(3)-应用工程(helloworld)构建

解决:

修改idea的启动参数,即在下图红框处文件中,在最后添加-Dfile.encoding=UTF-8

Activiti6.0学习实践(3)-应用工程(helloworld)构建

​​​​​​​8.2、流程定义获取name乱码

问题描述:

Activiti6.0学习实践(3)-应用工程(helloworld)构建

解决:

检查数据库中记录,发现也是乱码,推断是入数据库就出问题。检查发现mysql的url没有配置字符集,增加UTF-8配置,如下图红框,问题解决

Activiti6.0学习实践(3)-应用工程(helloworld)构建