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配置,如下圖紅框,問題解決

 

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