1.工作流的概念?
工作流:将生活中与审批流程线管的操作,通过计算机的方式去实现。
提供非常晚上的工作流,流程控制等相关功能。
JBPM:JBOSS收购,编程了jboss企业中间件的一员。
activiti:工作流就可以通过这个图形化的步骤去执行程序,这个图形的本质是xml文件。
activiti工作流是通过解析xml的方式去解析步骤。
图形与xml之间如何进行转化:BPMN2.0
Alfresco 软件在 2010 年 5 月 17 日宣布 Activiti 业务流程管理(BPM)开源项目的正式启动,其 首席架构师由业务流程管理 BPM 的专家 Tom Baeyens 担任,Tom Baeyens 就是原来 jbpm 的架构师, 而 jbpm 是一个非常有名的工作流引擎,当然 activiti 也是一个工作流引擎。 Activiti 是一个工作流引擎, activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务 流程由 activiti 进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的 健壮性,同时也减少了系统开发维护成本。
官方网站:https://www.activiti.org/
版本有:5.x,6.x,7.x
2.BPMNJS插件使用及汉化
2.1安装和配置nodejs 插件
2.1.1下载nodejs
https://nodejs.org/en
2.1.2安装nodejs,傻瓜式安装
安装之后在安装目录下创建node_cache和node_global两个目录
如果目录已经存在可以不创建
node_cache:作为缓存路径
node_global:作为全模块所在路径
2.1.3在cmd中使用命令修改默认的地址
下面两个地址是上面手动创建的
npm config set prefix "C:\Program Files\nodejs\node_global"
npm config set cache "C:\Program Files\nodejs\node_cache"
2.1.4配置nodejs环境变量
位置:右击计算机->属性->高级系统设置->环境变量->系统设置
2.1.5测试nodejs安装情况
如果版本不合适就修改版本号
本案例使用的版本是6.14.18版本
npm install -g npm@6.14.18
2.1.6修改默认的镜像地址
修改命令:npm config set registry https://registry.npm.taobao.org/
3.下载和配置BPMNJS插件
3.1案例中下载的是7.2.1版本
https://bpmn.io/
3.2直接解压下载的bpmnjs的,并进入到目录中
3.3进入到properties-panel目录中
在当前目录中打开cmd命令窗口
3.4在cmd命令行中执行npm install初始化bpmnjs
【执行命令效果如下】
【执行成功后,在propertis-panel目录中产生新的目录】
3.5在cmd命令行中执行npm run dev命令
命令成功后会直接通过浏览器弹出bpmnjs插件画图工具
默认的访问地址是:http://localhost:9013/
4.BPMNJS插件汉化
4.1在propertis-panel目录中创建目录
在该目录中创建changelanguage文件夹
4.2将汉化文件放到changelanguage目录中
汉化资源下载:
链接:https://pan.baidu.com/s/1gYTHrKZtgz32HD4C9oKxww
提取码:qzws
4.3修改默认的配置信息
修改配置主要是修改index.js文件中的默认加载项,将加载项换成是我们刚才拷贝的配置西信息。
【修改默认的配置信息1】
打开properties-panel/app/index.js配置文件
注释以下内容:
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda';
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda.json';
替换成:
import propertiesProviderModule from '../changelanguage/properties-panel/provider/activiti';
import activitiModdleDescriptor from '../changelanguage/activiti.json';
import customTranslate from '../changelanguage/customTranslate/customTranslate';
import customControlsModule from '../changelanguage/customControls';
【修改默认配置信息2】
注意以下内容:
var bpmnModeler = new BpmnModeler({
container: canvas,
propertiesPanel: {
parent: '#js-properties-panel'
},
additionalModules: [
propertiesPanelModule,
propertiesProviderModule
],
moddleExtensions: {
camunda: camundaModdleDescriptor
}
});
替换成:
var customTranslateModule = {
translate: ['value', customTranslate]
};
var bpmnModeler = new BpmnModeler({
container: canvas,
propertiesPanel: {
parent: '#js-properties-panel'
},
additionalModules: [
propertiesPanelModule,
propertiesProviderModule,
customControlsModule,
customTranslateModule
],
moddleExtensions: {
activiti:activitiModdleDescriptor
}
});
4.4在properties-panel目录中打开cmd重新执行命令
在cmd窗口中重新执行npm install 和 npm run dev两个命令
5springboot中使用activti
5.1导入pom依赖
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M6</version>
</dependency>
<dependency>
<groupId>org.activiti.dependencies</groupId>
<artifactId>activiti-dependencies</artifactId>
<version>7.1.0.M6</version>
<type>pom</type>
</dependency>
</dependencies>
注意因为activti需要操作表,默认使用的是mybatis,所以还要导入mybatis。还有就是activti7是高度集成了springsecurity,所以还要导入spring security的包。
5.2yml文件配置
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/activiti7
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
activiti:
history-level: audit #每次重启是否在部署信息表添加一条测试信息。
db-history-used: true #是否自动创建历史信息表
5.3使用activti
流程定义-ProcessDefinition和流程实例-ProcessInstance是一对多的关系
重点1:主要是对act_re_deployment和act_re_procedef表的相关操作
Deployement:添加资源文件、获取部署信息、部署时间
ProcessDefinition:获取版本号、key、资源名称、部署ID等。
重点2:RepositoryService:与部署和流程定义相关的service
5.3.1通过zip部署流程实例
//通过zip部署流程实例
@RequestMapping("/deployByZipResources")
@ResponseBody
public void deployByZipResources(){
InputStream in=this.getClass().getClassLoader().getResourceAsStream("bpmn/activiti1.zip");
ZipInputStream zipInputStream=new ZipInputStream(in);
Deployment deployment = repositoryService//与部署相关的service
.createDeployment()//创建部署对象
.name("请假管理1")
.addZipInputStream(zipInputStream)
.deploy();
System.out.println(deployment.getName());
}
5.3.2查看流程定义信息
//查看流程定义信息
@RequestMapping("/findProcessDefinition")
@ResponseBody
public void findProcessDefinition(){
String deploymentId="236467b5-3271-11ee-86d5-00bb607afddc";
ProcessDefinition processDefinition=
repositoryService.createProcessDefinitionQuery()
.deploymentId(deploymentId)
.singleResult();
System.out.println(processDefinition.getVersion());
}
5.3.3级联删除流程定义信息
注:如果想删除所有的流程定义信息,就查询所有的,然后遍历删除
//级联删除流程定义信息
@RequestMapping("/deleteProcessDefinition")
@ResponseBody
public void deleteProcessDefinition(){
String deploymentId="236467b5-3271-11ee-86d5-00bb607afddc";
repositoryService.deleteDeployment(deploymentId,true);
System.out.println("====删除成功====");
}
5.3.4查询资源文件信息
//查询资源文件信息
@RequestMapping("/findResources")
@ResponseBody
public void findResources() throws Exception{
//得到部署id
String deploymentId="c75d6479-3290-11ee-b02c-00bb607afddc";
//得到资源文件(png,bpmn)--List
String resourceName="";
List<String> resourcesNamelist=repositoryService
.getDeploymentResourceNames(deploymentId);
for (int i = 0; i < resourcesNamelist.size(); i++) {
if(resourcesNamelist.get(i).indexOf(".svg")>0){
resourceName=resourcesNamelist.get(i);
}
}
//输入流程关联源文件
InputStream is= repositoryService
.getResourceAsStream(deploymentId, resourceName);
//输出流关联目标文件
FileUtils.copyInputStreamToFile(is, new File("D://aa"+"//"+resourceName));
}
5.3.5获取最新版的流程定义信息
可以通过version降序排序,第一条就是最新版本
也可以通过map的key不能重复的原理,得到升序的最后一条
/**
* 如何查询出最新版本的流程定义
*/
@Test
public void queryNewProcessDefinition(){
String processDefinitionKey="leaveBill";
List<ProcessDefinition> list= processEngine.getRepositoryService()
.createProcessDefinitionQuery()
.processDefinitionKey(processDefinitionKey)
.orderByProcessDefinitionVersion().asc()
.list();
Map<String, Object> map=new HashMap<String, Object>();
for (int i=0;i<list.size();i++) {
map.put("version",list.get(i).getVersion());
}
System.out.println(map.get("version"));;
}
6流程变量
6.1UEL表达式
EL:Expression Language 表达式语言
UEL:Unified Express Language
语法描述: 统一表达式语言
基本用法:${money>200} 或 ${suggest==’批准’ || suggest==’驳回’}
流程变量表信息:act_run_variable act_hi_varinst
6.2URL保留字
and eq gt instanceof div or le false empty not lt ge
6.3UEL运算符
${a+b} ${a-b} ${a*b} ${a div b} ${a % b }
${a div 0}--Infinity ${a % 0 }--算数异常
6.4定义流程图
启动任务-使用map参数赋值
//启动流程,并设置办理人信息
@RequestMapping("/startProcessAndSetAssignee")
@ResponseBody
public void startProcessAndSetAssignee(){
Map<String,Object> map=new HashMap<>();
map.put("username","晓春");
String processDefinitionKey="procss_variable";
runtimeService.startProcessInstanceByKey(processDefinitionKey,map);
System.out.println("======启动成功======");
}
办理任务-使用实体类赋值
如果需要使用类传参,在画图时候,流程变量命名为:username.username
且使用的对象需要被序列化
//办理任务,并设置办理人信息
@RequestMapping("/completeAndSetAssignee")
@ResponseBody
public void completeAndSetAssignee(){
Map<String,Object> variables =new HashMap<>();
String taskId="89949385-34d8-11ee-b9f8-00bb607afddc";
map.put("username","张三");
taskService.setVariables(taskId,variables);
taskService.complete(taskId);
System.out.println("====任务办理成功====");
}
//办理任务,并设置办理人信息
@RequestMapping("/completeAndSetAssignee")
@ResponseBody
public void completeAndSetAssignee(){
Student stu=new Student("1001","张三");
Map<String,Object> map=new HashMap<>();
String taskId="5768d71f-34d9-11ee-9c63-00bb607afddc";
map.put("username",stu);
taskService.complete(taskId,map);
System.out.println("====任务办理成功====");
}
7设置流程变量--局部和全局变量
全局流程变量:设置全局流程变量,流程变量名称相同时,后一次的值替换前一次的值,而且可以看到ACT_HI_VARINST和ACT_RU_VARIABLE两张表中的TASK_ID全都为空
局部流程变量:设置局部流程变量,针对当前任务设置流程变量,如果一个流程中存在2个任务,对每个任务都设置局部变量,变量的名称相同时,后一次的版本的值也不会替换前一次版本的值,它会使用不同的任务ID作为标识,存放2个任务的流程变量值,而且可以看到TASK_ID的字段会存放任务ID的值,局部变量不会存入ACT_RU_VARIABLE表,且ACT_HI_VARINST表不会存入数据。
/设置流程变量
@RequestMapping("/setVariable")
@ResponseBody
public void setVariable(){
String taskId="798d60ed-34d9-11ee-b4eb-00bb607afddc";//任务id
Task task=taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
System.out.println(task.getProcessInstanceId());
//流程的task与报销自己的业务关联了。
taskService.setVariable(task.getId(), "报销金额", 10);
//局部变量
taskService.setVariableLocal(taskId, "报销的条目", "总经办支出");
taskService.setVariableLocal(taskId, "报销备注", "老总自己买烟");
//设置pojo类型的参数
Student stu=new Student("1001", "小春");
taskService.setVariable(taskId, "stu", stu);
}
查询历史的流程变量信息
//查询当前任务的流程变量信息
@RequestMapping("/getVariable")
@ResponseBody
public void getVariable(){
String taskId="798d60ed-34d9-11ee-b4eb-00bb607afddc";
Integer money=(Integer) taskService.getVariable(taskId, "报销金额");
System.out.println("==报销金额=="+money);
//查询对应流程的所有涉及到的变量
List<HistoricVariableInstance> list= historyService
.createHistoricVariableInstanceQuery()
.processInstanceId("77994404-34d7-11ee-a377-00bb607afddc")
.list();
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getVariableName());
}
}
指定多个候选人
8网关-排他、并行、包容
排他网关:通过设置连线条件,只能执行一个任务
并行网关:多个任务同时开启,多个任务都结束,任务结束
包容网关:只要满足条件就启动任务,多个任务都结束,任务结束
事件网关:基于某个事件,如事件,邮箱等
9查询工作流节点的连线信息
启动任务
//查询当前节点的连线信息
@RequestMapping("/getCurrentUserTaskConnection")
@ResponseBody
public void getCurrentUserTaskConnection(){
String taskId="06551f36-34e9-11ee-b663-00bb607afddc";
// 获取当前任务
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
//获取当前模型
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
// 获取当前节点
FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
UserTask userTask = (UserTask)flowElement;
//获取节点出口线段
List<SequenceFlow> list = userTask.getOutgoingFlows();
for (int i=0;i<list.size();i++){
System.out.println(list.get(i).getName());
}
}
10总结
我的分享就到这里,下一次分享使用activti7写一个请假的流程网站实例。