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

本章主要是通过构建一个流程应用,来了解通过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项目

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

2、创建一个maven工程

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

 

 

 

 

3、创建BPMN流程图

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

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

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

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

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

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

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

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

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

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

4、BPMN定义文件xml化

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

下面是本例中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. 创建流程引擎

    2. 部署流程定义文件xml

    3、启动流程

   4、处理流程

这一步主要是获取任务列表,并获取任务中的表单属性,对表单属性进行处理。上面代码中引入了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应用跑起来,则会一步一步进行任务处理,在每个任务界面进行表单内容的输入

​​​​​​​

 

8、问题处理小结

8.1、Idea工程报错, write-unsafe

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

解决:

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

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

问题描述:

解决:

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章