一.工作流介绍
1. 什么是工作流
工作流(Workflow),是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。
工作流将一套大的业务逻辑分解成业务逻辑段, 并统一控制这些业务逻辑段的执行条件,执行顺序以及相互通信,实现业务逻辑的分解和解耦。
做饭:
贷款审批:
2. 为什么要使用工作流
在企业日常的管理中,经常会有出差申请、加班申请、请假申请等流程。
如果用人工的方式管理这些流程,效率低,管理成本高。
因此为了提高效率,我们需要使用到工作流开发。
3. 使用工作流有什么好处
在工作流开发中,我们可以通过每一个流程定义清楚的看到业务的所有步骤,以及每一个流程实例运行到什么位置,参与者是谁;
能够节省更多的时间成本,提升企业信息化水平。
二. 工作流引擎
1. Camunda介绍
Camunda是一种工作流引擎,是由Java开发的一个纯Java库。
工作流引擎是用来开发工作流的框架。
市面上主流的工作流引擎有Activiti、Flowable、Camunda等。
|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Activiti | Activiti 由 Alfresco 公司开发,目前最高版本为 Activiti cloud 7.1.0。由于团队分歧 ,在Activiti6版本衍生出了Flowable。 |
| Flowable | Flowable是基于Activiti6衍生出来的版本,开发团队也是Activiti中分裂出来的,修复了Activiti6中的bug,并再此基础上实现的DMN、BPEL支持。 |
| Camunda | Camunda是基于Activiti5的,最新版本是Camunda7.17,开发团队也是从Activiti中分裂出来的,发展轨迹和Flowable相似。通过压力测试验证Camunda BPMN引擎性能和稳定性更好,功能完善;除了BPMN,Camunda还支持CMMN(案例管理)和DMN(决策自动化)。Camunda不仅带有引擎,还有很多强大的工具,用于建模、任务管理、监控和用户管理等。 |
Camunda BPM(业务流程管理)平台,用来管理,部署的流程定义、执行任务、策略等等。
下载安装一个Camunda平台,成功解压 Camunda 平台的发行版后,执行名为start.bat(对于 Windows 用户)或start.sh(对于 Unix 用户)的脚本。此脚本将启动应用程序服务器。
打开您的 Web 浏览器并导航到http://localhost:8080/以访问欢迎页面,Camunda的管理平台。
Camunda Modeler(用于编辑流程图及其他模型)平台,用来定义流程图,简单说就是一个画图工具。
下载 Modeler 后,只需将下载文件解压缩到您选择的文件夹中。
成功解压缩 zip 后,运行camunda-modeler.exe(对于 Windows 用户)、camunda-modeler.app(对于 Mac 用户)或camunda-modeler.sh(对于 Linux 用户)。
2. Camunda常用Api
RepositoryService
该服务提供了管理和操控流程部署和流程定义的操作方法。
(1)查询流程引擎所知道的部署和流程定义。
(2)挂起、激活流程定义。挂起意味着不能进行下一步的操作,而激活则是反操作。
(3)获取各种资源,比如部署种包含的文件,或者引擎自动生成的流程图等。
RuntimeService
处理已经启动的流程实例,查询流程实例和执行。
TaskService
需要被用户或者系统执行的任务是流程引擎的核心,跟任务有关的资源都在这个服务中:
(1)查询分配给用户或组的任务。
(2)创建新的独立任务。
(3)控制将任务分配给那个用户,或者那些用户,以及以何种方式参与到任务中。 认领并完成一个任务。认领是指某个用户决定承担某个任务。
FormService
获取表单相关的服务,可获取启动表单、审批表单,提交表单等操作。
HistoryService
获取执行的历史任务、历史的审批记录、参数、表单等信息。
三、学习步骤:
1、Camunda 官方快速入门教程中文版: https://zhuanlan.zhihu.com/p/375908620 或者 https://blog.csdn.net/zoollcar/article/details/117351192
Camunda Rest API 文档: https://docs.camunda.org/rest/camunda-bpm-platform/7.19/
Camunda 官网: https://camunda.com/
2、使用Nuget包 Camunda.Worker GitHub 地址: https://github.com/AMalininHere/camunda-worker-dotnet 找里面的samples文件夹下的使用Demo代码
3、在VS2022上写一个Demo
3.1、创建一个.net6 web空模板服务,然后安装Nuget包 Camunda.Worker
|---|--------------------------------------------------------------------------|
| 1 | <PackageReference Include=``"Camunda.Worker"
Version=``"0.13.5"
/>
|
3.2、Program.cs改成如下
|-------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | using
System.Collections.Generic;
using
System.Linq;
using
System.Threading.Tasks;
namespace
CamundaDemoWeb
{
``public
class
Program
``{
``public
static
void
Main(``string``[] args)
``{
``CreateHostBuilder(args).Build().Run();
``}
``public
static
IHostBuilder CreateHostBuilder(``string``[] args) =>
``Host.CreateDefaultBuilder(args)
``.ConfigureWebHostDefaults(webBuilder =>
``{
``webBuilder.UseStartup<Startup>();
``});
``}
}
|
3.3、Startup.cs 注入Camunda
using Camunda.Worker;
using Camunda.Worker.Client;
using CamundaDemoWeb.Handlers;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace CamundaDemoWeb
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddExternalTaskClient(client =>
{
//client.BaseAddress = new Uri("http://localhost:8080/engine-rest");
client.BaseAddress = new Uri("http://192.168.1.153:8080/engine-rest");
});
services.AddCamundaWorker("sampleWorker")
.AddHandler<SayHelloHandler>()
//.AddHandler<SayHelloGuestHandler>()
.ConfigurePipeline(pipeline =>
{
pipeline.Use(next => async context =>
{
var logger = context.ServiceProvider.GetRequiredService<ILogger<Startup>>();
logger.LogInformation("Started processing of task {Id}", context.Task.Id);
await next(context);
logger.LogInformation("Finished processing of task {Id}", context.Task.Id);
});
});
services.AddHealthChecks();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
}
3.4、写一个SayHelloHandler
using Camunda.Worker;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace CamundaDemoWeb.Handlers
{
//[HandlerTopics("sayHello", LockDuration = 10_000)]
//[HandlerVariables("USERNAME")]
[HandlerTopics("charge-card", LockDuration = 5_000)]
[HandlerVariables("amount")]
public class SayHelloHandler : IExternalTaskHandler
{
public async Task<IExecutionResult> HandleAsync(ExternalTask externalTask, CancellationToken cancellationToken)
{
await Task.CompletedTask;
//throw new System.NotImplementedException();
var username = externalTask.Variables["amount"].Value;
//await Task.Delay(1000);
return new CompleteResult
{
Variables = new Dictionary<string, Variable>
{
["MESSAGE"] = Variable.String("Hello, Guest!")
}
};
}
}
}