Business archives (业务归档)
为了部署流程,业务档案必须被封装,业务档案是activiti 引擎部署的单元,它相当于zip文件,它包含BPMN 2.0 processes, task forms, rules 和其它文件,可以说是一些资源文件的集合。
当一个业务归档被部署,它可以扫描扩展名是 .bpmn20.xml或.bpmn
注意: Java classes present in the business archive will not be added to the classpath.
部署方式
String barFileName = "path/to/process-one.bar"; ZipInputStream inputStream = new ZipInputStream(new FileInputStream(barFileName)); repositoryService.createDeployment() .name("process-one.bar") .addZipInputStream(inputStream) .deploy();
Deploying with Activiti Explorer
一个Activiti Explorer web应用允许上传 bar文件和单独的bpmn20.xml文件,选择管理页签点击Deployment
所有自定义的java类都可以在流程中使用
Versioning of process definitions 流程定义的版本控制
对每个流程定义都要完成 属性 key version name id的初始化
-
id 是流程定义的key
- name 流程定义的名字,并不是必须的
- 第一次部署有一个特殊的key,分配版本是1.后来的流程定义使用相同的key,版本每次加1,key用来区分流程定义的
-
id属性可以设置为 {processDefinitionKey}:{processDefinitionVersion}:{generated-id}
为流程中加图片资源
repositoryService.createDeployment()
.name("expense-process.bar")
.addClasspathResource("org/activiti/expenseProcess.bpmn20.xml")
.addClasspathResource("org/activiti/expenseProcess.png")
.deploy();
通过api可以再次获取图片资源
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("expense")
.singleResult();
String diagramResourceName = processDefinition.getDiagramResourceName();
InputStream imageStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), diagramResourceName);
如果不想生成流程图,isCreateDiagramOnDeploy 属性可以在流程引擎配置中设置
<propertyname="createDiagramOnDeploy"value="false"/>
Category
用户自己定义的目标名称空间,而不是使用默认的时:<definitions ... targetNamespace="yourCategory" ...
应该按照下面方式部署:
repositoryService
.createDeployment()
.category("yourCategory")
...
.deploy();
Defining a process
1, 创建xml文件,扩展名 是 .bpmn20.xml or .bpmn
2, 根元素 definitions
. 在它里面可以定义多个process。任何一个空的流程定义像下面那样. definitions
元素至少需要 xmlns
和 targetNamespace
声明.targetNamespace
可以是任意的, 对于分类管理流程定义很有用
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" targetNamespace="Examples"> <process id="myProcess" name="My First Process"> .. </process> </definitions>
可选的:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL
http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd
3, process 元素有两个属性
id: id是必须的属性,并且以map的key形式放到ProcessDefinition
对象中,id可以用来启动一个流程实例
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");
name : 可选属性,一般是给用户看的
4, 我们通过流程设计器,定义了如下内容的流程定义文件
<definitions id="definitions" targetNamespace="http://activiti.org/bpmn20" xmlns:activiti="http://activiti.org/bpmn" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"> <process id="financialReport" name="Monthly financial report reminder process"> <startEvent id="theStart" /> <sequenceFlow id='flow1' sourceRef='theStart' targetRef='writeReportTask' /> <userTask id="writeReportTask" name="Write monthly financial report" > <documentation> Write monthly financial report for publication to shareholders. </documentation> <potentialOwner> <resourceAssignmentExpression> <formalExpression>accountancy</formalExpression> </resourceAssignmentExpression> </potentialOwner> </userTask> <sequenceFlow id='flow2' sourceRef='writeReportTask' targetRef='verifyReportTask' /> <userTask id="verifyReportTask" name="Verify monthly financial report" > <documentation> Verify monthly financial report composed by the accountancy department. This financial report is going to be sent to all the company shareholders. </documentation> <potentialOwner> <resourceAssignmentExpression> <formalExpression>management</formalExpression> </resourceAssignmentExpression> </potentialOwner> </userTask> <sequenceFlow id='flow3' sourceRef='verifyReportTask' targetRef='theEnd' /> <endEvent id="theEnd" /> </process> </definitions>
5, 有了流程定义文件之后,我们需要部署这个流程定义文件
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("FinancialReportProcess.bpmn20.xml")
.deploy();
6, 部署之后,就可以启动一个流程实例了
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("financialReport"); //这个key就是流程定义中定义的process 的id
通过start事件后,流程会沿着start事件的所有输出流执行(该例子中
只有一个流),执行到第一个任务(“编制月度财务报表”)。
此时Activiti引擎会向持久化数据库中存储一个任务。此时,
关联在该任务上的用户或组的分配得以解析,并且也被存储到数据库中。
值得注意的是Activiti引擎会继续流程的执行步
骤直到流程执行进入一种等待状态,比如用户任务。
在这样一种等待状态,流程实例的当前状态被存储到数据库中。流
程会保持该状态直到有用户决定完成其任务。那时,流程引擎会继续执行流程直到流程进入一个新的等待状态或流程终
点。
其间,如果遇到流程引擎重启或崩溃的情况,流程状态也是安全的保存在数据库中。
流程的状态 时刻会在数据库中保存的
任务创建后,startProcessInstanceByKey 方法就会返回,因为用户任务的活动处于等待状态。该例子中,任务分配给了一
个组,这意味着该组中的每个成员都是任务执行的候选者。
7, 获取任务列表
List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit").list();
注意,我们传递给该方法的用户必须是accountancy组的成员,因为这在流程定义中进行了声明。
<potentialOwner> <resourceAssignmentExpression> <formalExpression>accountancy</formalExpression> </resourceAssignmentExpression> </potentialOwner>
我们也可以利用这个组名使用任务查询的API得到同样的结果。此时我们可以向代码中添加如下逻辑:
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
8, 会计现在需要认领此任务。通过认领任务,将有专人作为该任务的代理人(译注,代理人即为分配到任务的人或责任人),
同时该任务会从会计组其他成员的任务列表中消失。程序上完成认领任务如下
taskService.claim(task.getId(),"fozzie");
该任务现在存在于认领该任务的候选者的个人任务列表中
List<Task> tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
9, 完成任务
taskService.complete(task.getId());
10. 是否完成可以在历史中查看
HistoryService historyService = processEngine.getHistoryService();
HistoricProcessInstance historicProcessInstance =
historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
System.out.println("Process instance end time: "+ historicProcessInstance.getEndTime());
代码综述
public class TenMinuteTutorial{
publicstaticvoid main(String[] args){
// Create Activiti process engine
ProcessEngine processEngine =ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration()
.buildProcessEngine();
// Get Activiti services
RepositoryService repositoryService = processEngine.getRepositoryService();
RuntimeService runtimeService = processEngine.getRuntimeService();
// Deploy the process definition
repositoryService.createDeployment()
.addClasspathResource("FinancialReportProcess.bpmn20.xml")
.deploy();
// Start a process instance
String procId = runtimeService.startProcessInstanceByKey("financialReport").getId();
// Get the first task
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("accountancy").list();
for(Task task : tasks){
System.out.println("Following task is available for accountancy group: "+ task.getName());
// claim it
taskService.claim(task.getId(),"fozzie");
}
// Verify Fozzie can now retrieve the task
tasks = taskService.createTaskQuery().taskAssignee("fozzie").list();
for(Task task : tasks){
System.out.println("Task for fozzie: "+ task.getName());
// Complete the task
taskService.complete(task.getId());
}
System.out.println("Number of tasks for fozzie: "
+ taskService.createTaskQuery().taskAssignee("fozzie").count());
// Retrieve and claim the second task
tasks = taskService.createTaskQuery().taskCandidateGroup("management").list();
for(Task task : tasks){
System.out.println("Following task is available for accountancy group: "+ task.getName());
taskService.claim(task.getId(),"kermit");
}
// Completing the second task ends the process
for(Task task : tasks){
taskService.complete(task.getId());
}
// verify that the process is actually finished
HistoryService historyService = processEngine.getHistoryService();
HistoricProcessInstance historicProcessInstance =
historyService.createHistoricProcessInstanceQuery().processInstanceId(procId).singleResult();
System.out.println("Process instance end time: "+ historicProcessInstance.getEndTime());
}
}