1.后端搭建
搭建流程引擎后端的时候,主要注意springboot版本和Camunda版本之间的兼容性。此次springboot版本2.6.4,Camunda版本7.18.0。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.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>
pom文件配置好后,通过一般的注解入口@SpringBootApplication,即可启动Camunda流程引擎。
2.数据库改造
Camunda默认使用的数据库为自带的h2内存数据库,此时一般需要将其改成mysql数据库,在配置文件配置数据库即可,application.yaml如下:
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
一般Camunda会自动初始化mysql生成act_开头的49张表,如需手动初始化sql,可去官网找到对应版本(此例中Camunda版本为7.18.0)的sql脚本文件,https://camunda.com/download/,
下载windows安装压缩包,./configuration/sql目录下即可找到sql文件,engine和identity都执行。
不需要增加java代码或配置,直接启动即成功切换数据库。
3.流程接口文档
流程接口可以直接使用rest-api,参考官方文档https://docs.camunda.org/manual/7.18/reference/rest/。
a.部署流程
文档地址:https://docs.camunda.org/manual/7.18/reference/rest/deployment/post-deployment/
接口路径 POST /deployment/create
全路径:post http://localhost:8080/engine-rest/deployment/create
将流程文件 流程.bpmn 通过此接口即可完成流程部署,返回definitionId;
b.启动流程实例
文档地址https://docs.camunda.org/manual/7.18/reference/rest/process-definition/post-start-process-instance/
接口路径 POST /process-definition/{id}/start
其中id为上一步获取到的definitionId;
c.提交任务
接口路径 post /task/{id}/complete
d.获取待办任务
接口地址 get /task
参数assignee承办人,选用一对一模式(一个任务对应一个参与者)可通过此参数获取本人待办
参数candidateUser候选人,需要用到一对多模式,可用参数candidateUser获取本人待办
e.审批意见
接口地址 post /task/{id}/comment/create
当然,除了官方提供的rest-api,也可以自定义开发api,通过以下代码同样可以实现流程部署:
@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();
所有class类官方文档https://docs.camunda.org/javadoc/camunda-bpm-platform/7.18/allclasses.html
其中:
RepositoryService: 对流程定义即bpm文件的相关操作;
RuntimeService: 通过流程定义产生的流程实例,由RuntimeService操作
TaskService: 由用户去执行的任务的相关操作
IdentityService: 管理组和用户
FormService: 可选的表单服务
HistoryService: 历史记录服务
4.流程编辑器bpmn
可参考开源项目https://gitcode.net/mirrors/PL-FE/bpmn-camunda?utm_source=csdn_github_accelerator
编辑流程图bpmn文件:
<?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>
其中:”可执行文件“,这个选项需要勾选上,不然流程部署后,3.b.启动流程实例步骤获取不到definitionId
创建任务的时候,要选择用户任务
,而不是普通任务
默认的编辑器没有用户任务,需要在前端项目node_modules文件夹下找到
bpmn-js/lib/features/palette/paletteprovider.js
参照create.task添加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.设置参与者
assignee承办人对应用户任务的”代理人“属性,也可以选用一对多的candidateUser候选人或候选组
设置参与者的时候,可以直接写死参与者的id,也可以通过使用流程变量来动态设置参与者,格式如下:
${deptMajor}
其中流程变量deptMajor,在启动流程时候,需要定义数据类型(值可以先不定义)
参照接口3.b POST /process-definition/{id}/start
在请求体传入如下json数据,初始化流程变量:
{
"variables": {
"deptMajor" : {
"value" : "123",
"type": "String"
},
"orgMajor" : {
"value" : null,
"type": "String"
},
"flag" : {
"value" : 2,
"type": "Integer"
}
}
}
b.流程分支控制
设计流程图时,网关各分支增加条件,条件类型为表达式:${flag==1}
然后如上启动流程的时候给流程变量flag初始化和赋值,后续提交任务的时候,也可随时通过修改流程变量的值来控制流程分支的走向。
5.常用表
act_ge_bytearray 记录部署的bpmn流程文件
act_re_deployment 部署发布的流程会在此产生记录
act_re_procdef 已发布的流程定义(BPMN流程模型定义表)
act_hi_procinst 历史流程实例表
act_hi_actinst 历史活动实例表
act_hi_identitylink 历史任务执行人表
act_ru_task 任务表
act_ru_identitylink 任务执行人表
act_ru_execution BPMN流程运行时记录表
6.当前流程图高亮
基本思路为通过接口查出流程定义的xml内容,然后找到当前正在运行的节点,通过方法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>
效果如下:
具体js中初始化及方法可参考bpmn官网:bpmn-js walkthrough | Toolkits | bpmn.io