springboot integrates Camunda, plus front-end bpmn page process editor

1. Backend construction

When building the backend of the process engine, pay attention to the compatibility between the springboot version and the Camunda version. This time springboot version 2.6.4, Camunda version 7.18.0. The contents of the pom file are as follows:

<?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.6.4</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>camunda-demo2</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <springboot.version>2.6.4</springboot.version>
        <camunda.springboot.version>7.18.0</camunda.springboot.version>
        <java.version>1.8</java.version>
    </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-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
<!--            <scope>runtime</scope>-->
        </dependency>
<!--        <dependency>-->
<!--            <groupId>org.springframework.boot</groupId>-->
<!--            <artifactId>spring-boot-starter-test</artifactId>-->
<!--            <scope>test</scope>-->
<!--        </dependency>-->
        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter</artifactId>
            <version>${camunda.springboot.version}</version>
        </dependency>

        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-rest</artifactId>
            <version>${camunda.springboot.version}</version>
        </dependency>

        <dependency>
            <groupId>org.camunda.bpm.springboot</groupId>
            <artifactId>camunda-bpm-spring-boot-starter-webapp</artifactId>
            <version>${camunda.springboot.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

After the pom file is configured, the Camunda process engine can be started through the general annotation entry @SpringBootApplication.

2. Database transformation

The default database used by Camunda is the built-in h2 memory database. At this time, it is generally necessary to change it to a mysql database. Just configure the database in the configuration file. The application.yaml is as follows:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/cmd_dev?characterEncoding=UTF-8&useUnicode=true&useSSL=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456

camunda.bpm:
  admin-user:
    id: demo
    password: demo
    firstName: Tom
  filter:
    create: All tasks

Generally, Camunda will automatically initialize mysql to generate 49 tables starting with act_. If you need to manually initialize sql, you can go to the official website to find the sql script file of the corresponding version (in this case, the Camunda version is 7.18.0), https://camunda.com /download/ ,

Download the Windows installation compressed package, you can find the sql file in the ./configuration/sql directory, and execute both engine and identity.

There is no need to add java code or configuration, and the database can be successfully switched after starting directly.

3. Process interface document

The process interface can directly use rest-api, refer to the official document https://docs.camunda.org/manual/7.18/reference/rest/ .

a. Deployment process

Document address: https://docs.camunda.org/manual/7.18/reference/rest/deployment/post-deployment/

Interface path POST /deployment/create

Full path: post http://localhost:8080/engine-rest/deployment/create

Pass the process file process.bpmn through this interface to complete process deployment and return definitionId;

b. Start the process instance

Document address https://docs.camunda.org/manual/7.18/reference/rest/process-definition/post-start-process-instance/

Interface path POST /process-definition/{id}/start

Where id is the definitionId obtained in the previous step;

c. Submit the task

Interface path post /task/{id}/complete

d. Get to-do tasks

Interface address get /task

The parameter assignee is the undertaker. If you choose the one-to-one mode (one task corresponds to one participant), you can use this parameter to obtain your own to-do

The parameter candidateUser needs to use the one-to-many mode, and the parameter candidateUser can be used to obtain the personal to-do

e. Approval comments

Interface address post /task/{id}/comment/create

Of course, in addition to the official rest-api, you can also customize the development of api, and you can also implement process deployment through the following code:

    @Autowired
    private RepositoryService repositoryService;

    InputStream in;
    try {
        in= new FileInputStream("D:/ab/a.bpmn");
    } catch (FileNotFoundException e) {
        throw new RuntimeException(e);
    }
    Deployment deploy = repositoryService.createDeployment()
                .addInputStream("b.bpmn", in)    //流程定义文件名称
                .name("nameA")                    //流程部署名称
                .source("sourceA")                //流程部署source
                .deploy();

All class official documents https://docs.camunda.org/javadoc/camunda-bpm-platform/7.18/allclasses.html

in:

RepositoryService: Relevant operations on process definitions, namely bpm files;

RuntimeService: The process instance generated by the process definition is operated by RuntimeService

TaskService: related operations of tasks performed by users

IdentityService: Manage groups and users

FormService: optional form service

HistoryService: History service

4. Process editor bpmn

Refer to the open source project https://gitcode.net/mirrors/PL-FE/bpmn-camunda?utm_source=csdn_github_accelerator

Edit the flowchart bpmn file:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2" targetNamespace="http://bpmn.io/bpmn" exporter="bpmn-js (https://demo.bpmn.io)" exporterVersion="5.1.2">
  <process id="Process_7" name="流程7" isExecutable="true">
    <startEvent id="StartEvent_1y45yut" name="开始">
      <outgoing>Flow_0yq3fo1</outgoing>
    </startEvent>
    <userTask id="Activity_04i1hw0" name="审批7" camunda:assignee="${deptMajor}">
      <incoming>Flow_1ona6kc</incoming>
      <outgoing>Flow_0r1n32u</outgoing>
    </userTask>
    <userTask id="Activity_1x3adqc" name="结算7" camunda:assignee="${orgMajor}">
      <incoming>Flow_0yedygk</incoming>
      <outgoing>Flow_1kw655g</outgoing>
    </userTask>
    <endEvent id="Event_06xx78w">
      <incoming>Flow_0r1n32u</incoming>
      <incoming>Flow_1kw655g</incoming>
    </endEvent>
    <exclusiveGateway id="Gateway_19qnoe0">
      <incoming>Flow_0yq3fo1</incoming>
      <outgoing>Flow_1ona6kc</outgoing>
      <outgoing>Flow_0yedygk</outgoing>
    </exclusiveGateway>
    <sequenceFlow id="Flow_0yq3fo1" sourceRef="StartEvent_1y45yut" targetRef="Gateway_19qnoe0" />
    <sequenceFlow id="Flow_1ona6kc" sourceRef="Gateway_19qnoe0" targetRef="Activity_04i1hw0">
      <conditionExpression xsi:type="tFormalExpression">${flag==1}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="Flow_0yedygk" sourceRef="Gateway_19qnoe0" targetRef="Activity_1x3adqc">
      <conditionExpression xsi:type="tFormalExpression">${flag==2}</conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="Flow_0r1n32u" sourceRef="Activity_04i1hw0" targetRef="Event_06xx78w" />
    <sequenceFlow id="Flow_1kw655g" sourceRef="Activity_1x3adqc" targetRef="Event_06xx78w" />
  </process>
  <bpmndi:BPMNDiagram id="BpmnDiagram_1">
    <bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_7">
      <bpmndi:BPMNEdge id="Flow_1kw655g_di" bpmnElement="Flow_1kw655g">
        <omgdi:waypoint x="370" y="200" />
        <omgdi:waypoint x="500" y="200" />
        <omgdi:waypoint x="500" y="138" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0r1n32u_di" bpmnElement="Flow_0r1n32u">
        <omgdi:waypoint x="370" y="30" />
        <omgdi:waypoint x="500" y="30" />
        <omgdi:waypoint x="500" y="102" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0yedygk_di" bpmnElement="Flow_0yedygk">
        <omgdi:waypoint x="150" y="145" />
        <omgdi:waypoint x="150" y="200" />
        <omgdi:waypoint x="270" y="200" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_1ona6kc_di" bpmnElement="Flow_1ona6kc">
        <omgdi:waypoint x="150" y="95" />
        <omgdi:waypoint x="150" y="30" />
        <omgdi:waypoint x="270" y="30" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_0yq3fo1_di" bpmnElement="Flow_0yq3fo1">
        <omgdi:waypoint x="38" y="120" />
        <omgdi:waypoint x="125" y="120" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="StartEvent_1y45yut_di" bpmnElement="StartEvent_1y45yut">
        <omgdc:Bounds x="2" y="102" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <omgdc:Bounds x="10" y="145" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_04i1hw0_di" bpmnElement="Activity_04i1hw0">
        <omgdc:Bounds x="270" y="-10" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_1x3adqc_di" bpmnElement="Activity_1x3adqc">
        <omgdc:Bounds x="270" y="160" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_06xx78w_di" bpmnElement="Event_06xx78w">
        <omgdc:Bounds x="482" y="102" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Gateway_19qnoe0_di" bpmnElement="Gateway_19qnoe0" isMarkerVisible="true">
        <omgdc:Bounds x="125" y="95" width="50" height="50" />
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Among them: "Executable file", this option needs to be checked, otherwise, after the process is deployed, the definitionId cannot be obtained in the step 3.b. Start the process instance

When creating a task, select User Task

, instead of the normal task

The default editor has no user tasks and needs to be found under the node_modules folder of the front-end project

bpmn-js/lib/features/palette/paletteprovider.js

Reference create.task addition create.user-task:

    'create.task': createAction(
      'bpmn:Task', 'activity', 'bpmn-icon-task',
      translate('Create Task')
    ),
    'create.user-task': createAction(
      'bpmn:UserTask', 'activity', 'bpmn-icon-user-task',
      translate('Create User Task')
    ),

a. Set up participants

assignee The undertaker corresponds to the "agent" attribute of the user task, and one-to-many candidateUser candidates or candidate groups can also be selected

When setting a participant, you can directly write the id of the participant, or you can dynamically set the participant by using a process variable. The format is as follows:

${deptMajor}

Among them, the process variable deptMajor needs to define the data type when starting the process (the value can not be defined first)

Refer to interface 3.b POST /process-definition/{id}/start

Pass in the following json data in the request body to initialize the process variables:

{
  "variables": {
    "deptMajor" : {
        "value" : "123",
        "type": "String"
    },
    "orgMajor" : {
        "value" : null,
        "type": "String"
    },
    "flag" : {
        "value" : 2,
        "type": "Integer"
    }
  }
}

b. Process branch control

When designing the flowchart, add conditions to each branch of the gateway, and the condition type is an expression: ${flag==1}

Then initialize and assign values ​​to the process variable flag when starting the process as above. When submitting tasks later, you can also modify the value of the process variable at any time to control the direction of the process branch.

5. Common table

act_ge_bytearray records the deployed bpmn process file

The process of act_re_deployment deployment release will generate records here

act_re_procdef Published process definition (BPMN process model definition table)

act_hi_procinst historical process instance table

act_hi_actinst historical activity instance table

act_hi_identitylink Historical task executor table

act_ru_task task table

act_ru_identitylink task executor table

act_ru_execution BPMN process runtime record table

6. The current flow chart is highlighted

The basic idea is to find out the xml content of the process definition through the interface, then find the currently running node, and modify its style through the method canvas.addMarker(actId, 'highlight'):

<template>
  <div class="containers">
    <div id="canvas" ref="canvas"></div>
  </div>
</template>

<script>
  import BpmnViewer from 'bpmn-js'
  import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'
  let bpmnViewer = null
  const webUrl = "http://localhost:8095/camunda"
  export default {
    name: 'bpmnView',
    data () {
      return {
        msg: 'Welcome to yjr Vue.js App',
        bpmnModeler: null
      }
    },
    mounted() {
      bpmnViewer = new BpmnViewer({
        container: '#canvas',
        width: '100%',
        height: '100%',
        additionalModules: [
          MoveCanvasModule // 移动整个画布
        ]
      })
      this.greet()
    },
    methods: {
      createBpmnViewer :async function (bpmnXML) {
        try {
          await bpmnViewer.importXML(bpmnXML);
        } catch (err) {
          console.error('error loading BPMN 2.0 XML', err);
        }
        let canvas = bpmnViewer.get('canvas')
        canvas.zoom('fit-viewport', 'auto')
      },
      greet: function () {
            const that = this
            const processDefinitionId = this.$route.query.processDefinitionId
            this.$http.get(webUrl + '/engine-rest/process-definition/' + processDefinitionId + '/xml')
            .then((response)=>{
                if(response.data.bpmn20Xml){
                  that.createBpmnViewer(response.data.bpmn20Xml)
                  that.getAct();
                }
            })
            .catch((response)=>{
                console.log(response);
            })
        },
        getAct: function () {
          const that = this
          const processInstanceId = this.$route.query.processInstanceId
          let canvas = bpmnViewer.get('canvas')
          this.$http.get(webUrl + '/web/processInstance/getAct?processInstanceId=' + processInstanceId)
            .then((response)=>{
                if(response.data.code == 200){
                  let list = response.data.data;
                  for(var actId in list){
                    canvas.addMarker(list[actId], 'highlight');
                  }
                }
            })
            .catch((response)=>{
                console.log(response);
            })
        }
    }
  }
</script>
<style>
.highlight .djs-visual > :nth-child(1) {
  stroke: green !important;
  fill: rgba(0, 80, 0, 0.4) !important;
}
.djs-container{
    height: 80vh !important;
  }
</style>

The effect is as follows:

For specific js initialization and methods, please refer to the bpmn official website: bpmn-js walkthrough | Toolkits | bpmn.io

Guess you like

Origin blog.csdn.net/Yang_RR/article/details/129148106