总概

定义:工作流是在计算机支持下业务流程的自动或半自动化,其通过对流程进行描述以及按一定规则执行以完成相应工作。

应用:随着计算机技术的发展以及工业生产、办公自动化等领域的需求不断提升,面向事务审批、材料提交、业务整合和数据统计等应用需求的图文工作流、业务工作流也不断涌现。利用科学工作流还可以用于研究(地理)模型的集成。

研究内容

研究工作流可从工作流模型、工作流的定义和表达、工作流引擎

1.工作流模型

1.1面向控制:通常业务工作流大多数都是面向控制的工作流,以最常见的公司请假流程为例,当请假天数小于阈值时能向主管请假,否则只能向经理审批。

工作流入门这篇就够了!_xml

工作流入门这篇就够了!_数据_02编辑

1.2面向数据:通常面向数据是科学工作流处理的业务,以GIS水文分析为例,进行水文分析需要DEM数据,而且需要依次进行填挖、流向、汇流累积量等分析,通常前一步的输出结果常常为下一步的输入数据,此过程涉及到数据。因此,需选择面向数据的工作流模型。

工作流入门这篇就够了!_xml_03

工作流入门这篇就够了!_数据_04编辑

2.工作流的定义和表达

2.1.BPMN(Business Process Modeling Notation,即业务流程建模符号):是一种流程建模的通用和标准语言,用来绘制业务流程图,以便更好地让各部门之间理解业务流程和相互关系。

学习BPMN可去官网下载BPMN2规范文档,当然文档为全英文,需要一定英语功底

BPMN官网:BPMN Specification - Business Process Model and Notation

工作流入门这篇就够了!_数据_05

工作流入门这篇就够了!_数据_06编辑

2.1.1BPMN结构(以上述请假案例为例)

BPMN大致可以分为两部分,一部分为<process></process>标签内,对BPMN要素的描述,另一部分为<bpmndi></bpmndi>内包含其位置信息,保证个元素的相对位置与设计时一致。

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="leaveProcess" name="简单请假流程" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="请假申请"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="exclusivegateway1"></sequenceFlow>
    <userTask id="usertask2" name="杰里奥审批"></userTask>
    <sequenceFlow id="flow3" sourceRef="exclusivegateway1" targetRef="usertask2">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${day>0&&day<=3}]]></conditionExpression>
    </sequenceFlow>
    <userTask id="usertask3" name="汤姆逊审批"></userTask>
    <sequenceFlow id="flow4" sourceRef="exclusivegateway1" targetRef="usertask3">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${day>3}]]></conditionExpression>
    </sequenceFlow>
    <endEvent id="endevent2" name="End"></endEvent>
    <sequenceFlow id="flow6" sourceRef="usertask3" targetRef="endevent2"></sequenceFlow>
    <sequenceFlow id="flow7" sourceRef="usertask2" targetRef="endevent2"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_leaveProcess">
    <bpmndi:BPMNPlane bpmnElement="leaveProcess" id="BPMNPlane_leaveProcess">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="90.0" y="220.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="280.0" y="210.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1">
        <omgdc:Bounds height="40.0" width="40.0" x="430.0" y="218.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds height="55.0" width="105.0" x="610.0" y="70.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds height="55.0" width="105.0" x="610.0" y="370.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent2" id="BPMNShape_endevent2">
        <omgdc:Bounds height="35.0" width="35.0" x="870.0" y="221.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="125.0" y="237.0"></omgdi:waypoint>
        <omgdi:waypoint x="280.0" y="237.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="385.0" y="237.0"></omgdi:waypoint>
        <omgdi:waypoint x="430.0" y="238.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="450.0" y="218.0"></omgdi:waypoint>
        <omgdi:waypoint x="450.0" y="97.0"></omgdi:waypoint>
        <omgdi:waypoint x="610.0" y="97.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="450.0" y="258.0"></omgdi:waypoint>
        <omgdi:waypoint x="451.0" y="397.0"></omgdi:waypoint>
        <omgdi:waypoint x="610.0" y="397.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
        <omgdi:waypoint x="715.0" y="397.0"></omgdi:waypoint>
        <omgdi:waypoint x="887.0" y="397.0"></omgdi:waypoint>
        <omgdi:waypoint x="887.0" y="256.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
        <omgdi:waypoint x="715.0" y="97.0"></omgdi:waypoint>
        <omgdi:waypoint x="887.0" y="97.0"></omgdi:waypoint>
        <omgdi:waypoint x="887.0" y="221.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

工作流入门这篇就够了!_数据_07

2.1.2 核心概念

工作流入门这篇就够了!_数据_08

工作流入门这篇就够了!_xml_09编辑

工作流入门这篇就够了!_工作流引擎_10

工作流入门这篇就够了!_xml_11编辑

2.1.3设计器推荐

processon:最常见的在线绘图软件,也可绘制BPMNProcessOn思维导图流程图-在线画思维导图流程图_在线作图实时协作

Camunda Modeler:Camunda工作流设计器,桌面端,支持Window和Linux系统,功能十分强大,工作流节点、任务和事件的属性非常丰富!!!

https://camunda.com/platform/modeler/

工作流入门这篇就够了!_xml_12

工作流入门这篇就够了!_xml_13编辑

Bpmn.js:前端BPMN设计器,功能仅次于Camunda Modeler个人认为,但是需要不少前端知识没上较前两者较难。但由于是前端BPMN设计器,可以将其嵌入到自己的前后端项目中。

推荐学习教程:

官网:bpmn-js: BPMN 2.0 rendering toolkit and web modeler | Toolkits | bpmn.io

最全的BPMN.js中文教程:全网最详bpmn.js教材-基础篇 - 简书https://github.com/LinDaiDai/bpmn-chinese-document/blob/master/directory.md

项目:Bpmn.js+Vue,Gitee和Github都有不少项目

工作流入门这篇就够了!_数据_14

工作流入门这篇就够了!_工作流引擎_15编辑

3.工作流引擎

   工作流设计器设计好的BPMN,可以直接导出BPMN文件或者XML文件,而怎样控制BPMN文件执行这就得靠工作流引擎控制(图3.1)。工作流引擎的工作大致可分为:流程解释、流程执行、管理监控和调用应用这四部分(图3.2)。

工作流入门这篇就够了!_数据_16

工作流入门这篇就够了!_工作流引擎_17编辑

图3.1 工作流设计与工作流引擎关系 

工作流入门这篇就够了!_工作流引擎_18

工作流入门这篇就够了!_工作流引擎_19编辑

图3.2工作流引擎作用 

现三个主流工作流引擎Activiti、Flowable、Camunda比较与推荐:

1.开源:推荐Activiti(完全开源)、Camunda和Flowable(部分开源,分开源和商业版)

2.新颖、学习资料、功能:Camunda>Flowable>Activiti,Camunda相比更新颖强大(个人感觉)

3.集成Spring-Boot前后端分离项目:Camunda>Flowable>Activiti(个人观点)

activiti这功能较少,很多功能都需要自行开发;flowable6.5版本作为最后一个支持Spring Boot 1.5.x和Spring 4.x的版本,后续版本不在提供支持,form表单模块已经商业化,开源版已经不再维护; Ca- munda开源版的功能肯定是要比activiti7功能多些的,而且Camunda的内部运行的性能更好;

优质推文:常见的工作流引擎(osworkflow、jbpm、activiti、flowable、camunda)比较 - 知乎

Activiti:Open Source Business Automation | Activiti

Flowable:Open Source

Camunda: https://camunda.com/   Camunda 中文站 | docs.camunda.orghttps://camunda.com/   

学习资料分享:

B站视频:🔍Activiti、Flowable、Camunda或工作流引擎

推荐网站:自称最全工作流文档 :仿钉钉飞书企业微信流程设计器

项目推荐:

入门:

Activiti项目:(了解工作流引擎最基本流程:部署、启动、挂载、激活等操作)

同时还可以结合B站视频或者Activiti或者Camunda自带的工作流工作可视化页面

工作流入门这篇就够了!_工作流引擎_20

工作流入门这篇就够了!_工作流引擎_21编辑

工作流执行的最基本流程:

工作流入门这篇就够了!_工作流引擎_22

工作流入门这篇就够了!_工作流引擎_23编辑

GitHub - jellyleo/activiti7: springboot2集成activiti7的工作流项目

集成开发:

仿钉钉系列:

dingding-mid-business-java: 仿钉钉飞书企业微信样式设计器,基于Flowable,Camunda

Ruoyi-Flowable-Plus:RuoYi-Flowable-Plus: 本项目基于 RuoYi-Vue-Plus 进行二次开发扩展Flowable工作流功能,支持在线表单设计和丰富的工作流程设计能力。如果觉得这个项目不错,麻烦点个star🌟。

更多上gitee或者github🔍类似关键词

3.1.Activiti

1.基本流程

BPMN部署(BPMN或者ZIP文件)

/**
	 * 
	 * 功能描述:classpath部署流程
	 *
	 * @param request
	 * @param response
	 * @see [相关类/方法](可选)
	 * @since [产品/模块版本](可选)
	 */
	@RequestMapping(value = "/deploy")
	@ResponseBody
	public String deploy(HttpServletRequest request, HttpServletResponse response) {

		String name = request.getParameter("name");
		String resource = request.getParameter("resource");

		if (StringUtils.isEmpty(resource) || StringUtils.isEmpty(name)) {
			return "param error";
		}

		try {
			// 创建一个部署对象
			Deployment deploy = repositoryService.createDeployment().name(name)
					.addClasspathResource("processes/" + resource).deploy();
			System.out.println("部署成功:" + deploy.getId());
			System.out.println("*****************************************************************************");
		} catch (Exception e) {
			return "fail";
		}
		return "success";
	}

	/**
	 * 
	 * 功能描述:zip部署流程
	 *
	 * @param request
	 * @param response
	 * @see [相关类/方法](可选)
	 * @since [产品/模块版本](可选)
	 */
	@RequestMapping(value = "/deploy/zip")
	@ResponseBody
	public String deployZip(HttpServletRequest request, HttpServletResponse response) {

		String name = request.getParameter("name");
		String zip = request.getParameter("zip");

		if (StringUtils.isEmpty(zip) || StringUtils.isEmpty(name)) {
			return "param error";
		}

		try {
			InputStream in = this.getClass().getClassLoader().getResourceAsStream("processes/" + zip);
			ZipInputStream zipInputStream = new ZipInputStream(in);
			Deployment deployment = repositoryService// 与流程定义和部署对象相关的Service
					.createDeployment()// 创建一个部署对象
					.name(name)// 添加部署名称
					.addZipInputStream(zipInputStream)// 完成zip文件的部署
					.deploy();// 完成部署
			System.out.println("部署ID:" + deployment.getId());
			System.out.println("部署名称:" + deployment.getName());
			System.out.println("*****************************************************************************");
		} catch (Exception e) {
			return "fail";
		}
		return "success";
	}

工作流入门这篇就够了!_工作流引擎_24

启动(启动流程,可得到一个流程实例)与删除流程

@RequestMapping(value = "/start")
	@ResponseBody
	public String start(HttpServletRequest request, HttpServletResponse response) {

		String processDefinitionKey = request.getParameter("processId");
		String variable = request.getParameter("variable");

		if (StringUtils.isEmpty(processDefinitionKey)) {
			return "param error";
		}

		try {
			Map<String, Object> variables = new HashMap<>();
			if (!StringUtils.isEmpty(variable)) {
				CommonVariable variablesEntity = JSON.parseObject(variable, CommonVariable.class);
				variables = BeanUtil.beanToMap(variablesEntity);
			}

			ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefinitionKey, variables);
//			// Businesskey:业务标识,通常为业务表的主键,业务标识和流程实例一一对应。业务标识来源于业务系统。存储业务标识就是根据业务标识来关联查询业务系统的数据
//			ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey,
//					variables);

			System.out.println("流程实例ID:" + instance.getId());
			System.out.println("流程定义ID:" + instance.getProcessDefinitionId());
			System.out.println("*****************************************************************************");
		} catch (Exception e) {
			e.printStackTrace();
			return "fail";
		}
		return "success";
	}



	/**
	 * 
	 * 功能描述:删除流程
	 *
	 * @param request
	 * @param response
	 * @see [相关类/方法](可选)
	 * @since [产品/模块版本](可选)
	 */
	@RequestMapping(value = "/delete")
	@ResponseBody
	public String deleteProcess(HttpServletRequest request, HttpServletResponse response) {

		String processId = request.getParameter("processId");

		if (StringUtils.isEmpty(processId)) {
			return "param error";
		}

		try {
			runtimeService.deleteProcessInstance(processId, "流程已完毕");
			System.out.println("终止流程");
			System.out.println("*****************************************************************************");
		} catch (Exception e) {
			return "fail";
		}
		return "success";
	}

工作流入门这篇就够了!_工作流引擎_25

 流程实例挂载与激活

/**
	 * 
	 * 功能描述:流程实例挂起
	 *
	 * @param request
	 * @param response
	 * @see [相关类/方法](可选)
	 * @since [产品/模块版本](可选)
	 */
	@RequestMapping(value = "/instance/suspend")
	@ResponseBody
	public String suspendProcessInstance(HttpServletRequest request, HttpServletResponse response) {

		String processInstanceId = request.getParameter("processInstanceId");

		if (StringUtils.isEmpty(processInstanceId)) {
			return "param error";
		}

		try {
			// 根据一个流程实例的id挂起该流程实例
			runtimeService.suspendProcessInstanceById(processInstanceId);
			ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
					.processInstanceId(processInstanceId).singleResult();
			System.out.println("流程实例ID:" + processInstance.getId());
			System.out.println("流程定义ID:" + processInstance.getProcessDefinitionId());
			System.out.println("流程实例状态:" + processInstance.isSuspended());
			System.out.println("*****************************************************************************");
		} catch (Exception e) {
			return "fail";
		}
		return "success";
	}
/**
	 * 
	 * 功能描述:流程实例激活
	 *
	 * @param request
	 * @param response
	 * @see [相关类/方法](可选)
	 * @since [产品/模块版本](可选)
	 */
	@RequestMapping(value = "/instance/activate")
	@ResponseBody
	public String activateProcessInstance(HttpServletRequest request, HttpServletResponse response) {

		String processInstanceId = request.getParameter("processInstanceId");

		if (StringUtils.isEmpty(processInstanceId)) {
			return "param error";
		}

		try {
			// 根据一个流程实例id激活该流程
			runtimeService.activateProcessInstanceById(processInstanceId);
			ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
					.processInstanceId(processInstanceId).singleResult();
			System.out.println("流程实例ID:" + processInstance.getId());
			System.out.println("流程定义ID:" + processInstance.getProcessDefinitionId());
			System.out.println("流程实例状态:" + processInstance.isSuspended());
			System.out.println("*****************************************************************************");
		} catch (Exception e) {
			return "fail";
		}
		return "success";
	}

工作流入门这篇就够了!_xml_26

流程定义的挂载与激活

/**
	 * 
	 * 功能描述:流程定义挂起
	 *
	 * @param request
	 * @param response
	 * @see [相关类/方法](可选)
	 * @since [产品/模块版本](可选)
	 */
	@RequestMapping(value = "/definition/suspend")
	@ResponseBody
	public String suspendProcessDefinition(HttpServletRequest request, HttpServletResponse response) {

		String processDefinitionId = request.getParameter("processDefinitionId");

		if (StringUtils.isEmpty(processDefinitionId)) {
			return "param error";
		}

		try {
			// 根据一个流程定义的id挂起该流程实例
			repositoryService.suspendProcessDefinitionByKey(processDefinitionId);
			ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
					.processDefinitionKey(processDefinitionId).singleResult();
			System.out.println("流程定义ID:" + processDefinition.getId());
			System.out.println("流程定义状态:" + processDefinition.isSuspended());
			System.out.println("*****************************************************************************");
		} catch (Exception e) {
			return "fail";
		}
		return "success";
	}
/**
	 * 
	 * 功能描述:流程实例激活
	 *
	 * @param request
	 * @param response
	 * @see [相关类/方法](可选)
	 * @since [产品/模块版本](可选)
	 */
	@RequestMapping(value = "/instance/activate")
	@ResponseBody
	public String activateProcessInstance(HttpServletRequest request, HttpServletResponse response) {

		String processInstanceId = request.getParameter("processInstanceId");

		if (StringUtils.isEmpty(processInstanceId)) {
			return "param error";
		}

		try {
			// 根据一个流程实例id激活该流程
			runtimeService.activateProcessInstanceById(processInstanceId);
			ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
					.processInstanceId(processInstanceId).singleResult();
			System.out.println("流程实例ID:" + processInstance.getId());
			System.out.println("流程定义ID:" + processInstance.getProcessDefinitionId());
			System.out.println("流程实例状态:" + processInstance.isSuspended());
			System.out.println("*****************************************************************************");
		} catch (Exception e) {
			return "fail";
		}
		return "success";
	}

工作流入门这篇就够了!_数据_27

2.SpringBoot集成Activiti设计器

推荐推文:

Activiti6.0(十三)整合官方流程设计器_activiti6提供的web设计器-CSDN博客

Springboot+Activiti6+在线流程编辑器整合_activiti在线流程设计器-CSDN博客

3.2 Camunda

3.3Flowable