1 概念
-
工作流Workflow:
-
工作流系统:对系统的业务流程进行自动化管理
-
工作流引擎:如Activiti,用专门的建模语言如BPMN进行定义业务流程,预先定义好流程然后执行
-
BPM:业务流程管理Business Process Management;一种规范化的构造端到端的业务流程,提高组织业务效率;BPMN:业务流程模型和符号(图形)
2 应用
2.1 过程
-
部署Activiti:引入相关依赖
-
流程定义:使用Activiti流程建模工具定义业务流程,生成.bpmn文件;然后部署此定义的流程即存储内容到数据库
-
启动流程实例ProcessInstance:
-
用户查询待办任务Task
-
用户办理任务
-
流程实例结束
2.2 环境准备
-
引入依赖;同时需要数据库支持
-
IDE安装流程设计器:如IDEA上安装actiBPM插件
-
Activiti配置:
-
以默认方式创建相关表:resources目录下创建和编写activiti.cfg.xml文件,主要配置流程引擎配置类即ProcessEngineConfiguration用于创建ProcessEngine;与Spring整合后可使用Spring的配置文件
-
创建Java工具类,用来生成默认的25张相关表;一般配合Junit的@Test来运行
@Test public class TableBuilder { public void createTable() { // 读取默认的activiti.cfg.xml文件,生成流程引擎 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("...xml"); 使用读取配置文件来创建 } }
-
-
表结构:
-
act_ge_*:通用的流程定义和流程资源;系统相关属性
-
act_hi_*:流程历史记录
-
act_re_*:流程定义内容及静态资源
-
act_ru_*:流程运行实例
-
-
表对应的类关系图:表不由开发去定义实体、dao和service,而是由相关工具类实现,如ProcessEngine、RepositoryService(资源管理类,操作re相关表)、TaskService(任务管理类)、RuntimeService(流程运行管理类,操作ru相关表)、HistoryService(历史管理类,操作hi相关表)、ManagerService(引擎管理类)等
2.3 入门
2.3.1 定义流程
-
流程符号:
-
事件Event:开始事件StartEvent、中间事件IntermediateEvent、结束事件EndEvent
-
活动Activity:即工作work或任务task
-
网关GateWay:更灵活的分配分支走向
-
排他:按照输出流顺序计算,以结果为true的线路被选择执行,多个都为true时先择id最小的;都不为true时引擎抛出异常
-
并行:
-
拆分:并行执行所有输出顺序流,为每一条顺序流创建一个并行执行路线
-
合并:所有路线需等到全部执行完才继续向后执行
-
-
包容:自定义设置任意条执行线路
-
综合、事件
-
-
-
流程设计:创建并编写.bpmn文件:画出流程符号构成的图,设置property属性和对应的value
-
流程定义:.bpmn实质也是xml文件;因此可以修改后缀为.xml,有需要的也可到处为图片(给其他人看直观图而不是xml里的代码)
2.3.2 部署流程
// 创建ProcessEngine:
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取RepositoryService:
RepositoryService repositoryService = processEngine .getRepositoryService:RepositoryService ();
// 使用Service部署流程,定义流程名字,将.bpmn和图片部署到数据中:
Deployment deployment = repositoryService.createDeployment()
.name("...申请")
.addClasspathResource("...bpmn")
.addClasspathResource("....png")
.deploy();
// 获取属性信息:
deployment.getId()/getName();
// 运行后日志可看到会向25张相关表中操作数据
// 实际应用中不这样一个一个的add(),而是使用工具类打包后批量部署、
InputeStream inputeStream = this.getClass().getClassLoader().getResourceAsStream("包含了bpmn和png文件的zip压缩包文件所在路径");
ZipInputeStream zipInputeStream = new ZipInputeStream(inputeStream);
deployment = repositoryService.createDeployment()
.addZipInputStream(zipInputeStream)
.deploy();
2.3.3 流程启动与任务执行
// 创建ProcessEngine,获取RuntimeService,TaskService等;运行日志可看到各种数据操作的SQL
// 根据流程id启动流程:
ProcessInstance instance runtimeService.startProcessInstanceByKey("id");
// 获取流程内容:
instance.getId();
instance.getProcessDefinitionId();
instance.getActivityId();
// 任务创建与获取
TaskService taskService = processEngine.getTaskService();
List<TaskService> taskList taskService.createTaskQuery()
.processDefinitionKey("id")
.taskAssignee("角色") // 负责人
.list();
// for循环后获取任务中的各种属性;其他工具类Service同理
// 执行任务
taskService.complete("taskId");
// 流程删除
repositoryService.deleteDeployment("id"); // 不会删除历史信息表中数据;参数2可指定是否级联删除,级联删除用来解决某些不能删除的情形
// 流程的挂起与激活
repositoryService.activateProcessDefinitionById(...); // 参数中制定了流程id,则流程中全部操作都被挂起或激活即批量操作;通过runtimeService获取单个流程实例,可针对单个实例实现激活和挂起
repositoryService.suspendProcessDefinitionById(...);
// 下载资源文件
ProcessDefinition processDefiniton = repositoryService.createProcessDefinition()
.processDefinitionKey("id")
.singleResult();
String deploymentId = processDefiniton.getDeploymentId();
String pngResource = processDefiniton.getDiagramResourceName();
String bpmnResource = processDefiniton.getDResourceName();
InputeStream pngInputeStream = repositoryService.getResourceAsStream(deploymentId, pngResource);
InputeStream bpmnInputeStream = repositoryService.getResourceAsStream(deploymentId, bpmnResource);
File file = new File("资源存放路径+文件名");
FileOutStream out = new FileOutputStream(file);
IOUtils.copy(pngInputeStream, out); // IOUtils.copy(pngInpbpmnInputeStreamuteStream, out);
// 关闭流
// 流程历史查询
HistoryService historyService = processEngine.getHistoryService();
HistoricActivityInstanceQuery historicActivityInstanceQuery historyService.createHistoricActivityInstanceQuery();
historicActivityInstanceQuery.processInstanceId("instance_id"); // 还有根据其他id查询,具体可查看表中字段
3 结合实际业务
3.1 关联
-
Activiti的表与实际业务表相关联:启动流程实例时指定businessKey:
ProcessInstance processInstacne = runtimeService.startProcessInstanceByKey("key1", "key2"); // key1为流程定义id,key2为businessKey即业务表(如请假单)的某条数据id
3.2 任务分配
-
流程变量:用来控制流程分支即业务流程走向;类型支持常用Java基本数据类型和引用类型;作用域可以为一个流程实例PrecessInstance,或一个任务Task,或一个执行实例Execution;设置流程变量可在流程启动时、任务办理时、或通过流程实例、当前任务来设置;默认为全局变量,设置为local则需要显式调用setVariblesLocal();使用变量:
-
在属性上使用UEL表达式:如${key}
-
在连线上使用UEL表达式:如${sum > 100},${user.id = 1};类似条件表达式
-
-
任务分配给负责人;方式有:
-
固定分配:画流程图时直接指定Assigness属性的value;实际中不应以此固定写死
-
表达式分配:使用UEL表达式指定Assigness属性的value;UEL_value方式类似占位符,使用${}占位,引用配置定义的key,如${key};UEL_method方式则通过引用变量的属性来设置,如${user.getId()};还支持其他表达式如运算表达式
public class Evection implements Serializeble { private long id; private double sum; } Evection evection = new Evection(); evection.setId(1); evection.setSum(101); Map<String, Object> map = new HashMap<>(); map.put("key1", "负责人1"); // 实际业务中这些值可能来自数据库业务表 map.put("key2", "负责人2"); // map.put("key", evection); runtimeService.startProcessInstanceByKey("流程实例id", map);
-
监听器分配:指定TaskListeners属性值,包括指定Event、Type、Class、Fields等子集属性
-
实现监听器并指定给Class属性:
public class MyTaskListener implements TaskListener { // 指定负责人 @Override public void notify(DeplegateTask delegateTask) { if ("任务名称".equals(delegateTask.getName()) && "create".equals(delegateTask.getEventName())) { delegateTask.setAssigness("负责人"); } } }
-
-
-
任务查询:查询当前任务存在且负责人无误,才去执行任务完成
-
组任务:多个备选负责人设置为一组:指定CandidateUsers属性;候选人不能立即办理业务;所有候选人可拾取任务,成为该任务当前责任人;也可归还任务到组任务;getCandidateUsers()传入候选人名称查询组任务;任务交接