activiti學習筆記二
上一篇文章大概講了下什麼是流程引擎,為什麼我們要用流程引擎,他的基本原理是啥,以及怎麼進行基本的使用,這篇文章我們再講下其他的一些使用。
刪除流程部署
package activiti02;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
/**
* 刪除流程部署
* 影響了三張表:
* act_ge_bytearray
* act_re_deployment
* act_re_procdef
* 歷史表資訊會被保留,如果級聯刪除,會把全部記錄刪除
* */
public class ActivitiDeleteProcessDefinition {
public static void main(String[] args) {
// 1、創建ProcessEngine流程引擎對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到Repositoryervice實例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、查詢流程部署
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("holiday")
.singleResult();
// 4.1、刪除流程定義
// repositoryService.deleteDeployment(processDefinition.getDeploymentId());
// 4.2、如果還有未結束的流程節點,可以使用級聯刪除(true)
// deleteDeployment(String deploymentId, boolean cascade)
repositoryService.deleteDeployment(processDefinition.getDeploymentId(),true);
}
}
刪除流程實例
package activiti02;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import java.util.List;
/**
* 刪除流程實例
* 歷史表資訊會被保留
* */
public class ActivitiDeleteProcessInstance {
public static void main(String[] args) {
// 1、創建ProcessEngine流程引擎對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().taskAssignee("zhangsan").singleResult();
List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery()
.processInstanceId(task.getProcessInstanceId()).list();
for (ProcessInstance processInstance : processInstanceList) {
runtimeService.deleteProcessInstance(processInstance.getId(),"刪除流程實例");
}
System.err.println("ok");
}
}
如果流程實例刪除了,那這次的流程就不用再繼續執行了。act_ru_* 表的相關記錄都刪除
掛起/激活流程定義:
package activiti03;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
/**
* 掛起全部流程實例,使其無法啟動新的流程實例,未執行完的流程實例也不允許繼續執行
*
* */
public class ActivitiSuspendAllProcessInstance {
public static void main(String[] args) {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到repositoryService對象
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、查詢流程定義的對象
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("holiday")
.singleResult();
// 4、得到當前流程定義的實例是否都為暫停狀態
boolean suspended = processDefinition.isSuspended();
// 5、判斷
if (suspended) {
// 5.1、如果是暫停,那就全部激活
repositoryService.activateProcessDefinitionById(processDefinition.getId(),true,null);
System.err.println("流程定義:" + processDefinition.getId() + "激活");
}else {
// 5.2、如果是活動狀態,那就全部掛起
repositoryService.suspendProcessDefinitionById(processDefinition.getId(),true,null);
System.err.println("流程定義:" + processDefinition.getId() + "掛起");
}
}
}
掛起流程定義後,就不能再創建流程實例了,同時未完成的流程實例、流程任務也無法繼續完成。
掛起/激活單個流程實例:
package activiti03;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
/**
* 掛起指定一個流程實例,使其無法續執行。
* 給流程定義依舊可以發起新的流程實例,其他流程實例不受影響
*
* 和掛起全部區別:
* 掛起全部是針對流程定義來的,當流程定義被掛起後,該流程定義下的所有流程實例都自動被掛起
* 掛起一個是針對具體的流程實例來的,只掛起一個流程實例,並不會影響整個流程定義,也不會影響其他流程實例
* */
public class ActivitiSuspendSingleProcessInstance {
public static void main(String[] args) {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到runtimeService對象
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、查詢流程實例的對象
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processDefinitionKey("holiday")
.singleResult();
// 4、得到當前流程實例的實例是否都為暫停狀態
boolean suspended = processInstance.isSuspended();
// 5、判斷
if (suspended) {
// 5.1、如果是暫停,那就全部激活
runtimeService.activateProcessInstanceById(processInstance.getId());
System.err.println("流程實例定義id:" + processInstance.getId() + "激活");
}else {
// 5.2、runtimeService,那就全部掛起
runtimeService.suspendProcessInstanceById(processInstance.getId());
System.err.println("流程實例定義id:" + processInstance.getId() + "掛起");
}
}
}
activiti流程綁定業務記錄(BusinessKey):
package activiti03;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
/**
* activiti與自定義業務結合。
* 原理就是在啟動activiti流程實例的時候,傳一個業務流程數據的唯一id進來。
* 也就是說,activiti只是負責管理流程的推進,業務數據則是由我們自己來進行處理。
* 兩者通過act_ru_execution表的business_key來進行關聯
* */
public class ActivitiBusinessKey {
public static void main(String[] args) {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到RuntimeService對象
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、得到流程實例,需要直到流程定義的key,也就是流程process文件的Id,可以在bpmn裡面查看,也可以在資料庫act_re_procdef找到該流程的key
// startProcessInstanceByKey(String processDefinitionKey, String businessKey)
// 假設我們的業務請假id為1001
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday","1001");
// 4、輸出相關資訊
System.out.println("流程部署id ===> "+processInstance.getDeploymentId());
System.out.println("流程實例id ===> "+processInstance.getProcessInstanceId());
System.out.println("活動id ===> "+processInstance.getActivityId());
System.out.println("business_key ===> "+processInstance.getBusinessKey());
}
}
其實也就是在啟動流程實例的時候,就綁定一個我們自己的業務key,這樣以後我們就可以根據這個businessKey來我們自己的表查詢相關業務
查詢歷史節點記錄:
package activiti02;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import java.util.List;
/**
* 歷史數據查詢
* */
public class ActivitiHistoryQuery {
public static void main(String[] args) {
// 1、創建ProcessEngine流程引擎對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到HistoryService實例
HistoryService historyService = processEngine.getHistoryService();
// 3、獲得HistoricActivityInstanceQuery對象,一個查詢器
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
// 4、設置條件,並查詢
HistoricActivityInstanceQuery historicActivity = historicActivityInstanceQuery.processInstanceId("12501");
List<HistoricActivityInstance> historicActivityInstanceList = historicActivity.orderByHistoricActivityInstanceStartTime()
.asc().list();
// 5、輸出流程定義
for (HistoricActivityInstance processDefinition : historicActivityInstanceList) {
System.out.println("節點id==》"+processDefinition.getActivityId());
System.out.println("節點名==》"+processDefinition.getActivityName());
System.out.println("流程定義id==》"+processDefinition.getProcessDefinitionId());
System.out.println("流程實例id==》"+processDefinition.getProcessInstanceId());
System.out.println();
}
}
}
查詢流程定義:
package activiti02;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import java.util.List;
public class ActivitiQueryProcessDefinition {
public static void main(String[] args) {
// 1、創建ProcessEngine流程引擎對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到Repositoryervice實例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、獲得ProcessDefinitionQuery對象,一個查詢器
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
// 4、設置條件,並查詢出當前的所有流程定義
List<ProcessDefinition> processDefinitionList = processDefinitionQuery.processDefinitionKey("holiday")
.orderByProcessDefinitionVersion() // 設置排序
.desc().list();
// 5、輸出流程定義
for (ProcessDefinition processDefinition : processDefinitionList) {
System.out.println("流程定義id==》"+processDefinition.getId());
System.out.println("流程定義key==》"+processDefinition.getKey());
System.out.println("流程定義名==》"+processDefinition.getName());
System.out.println("流程定義version==》"+processDefinition.getVersion());
System.out.println("流程部署id==》"+processDefinition.getDeploymentId());
}
}
}
導出流程文件bpmn和圖片:
package activiti02;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.commons.io.IOUtils;
import java.io.*;
/**
* 需求:
* 1、從activiti的act_ge_bytearray讀取兩個資源文件
* 2、將這兩個資源文件放到指定目錄
*
* 實現方案:
* 1、使用activiti自帶的api,調用IO流轉換,輸出到磁碟
* 2、使用jdbc的對blob類型、clob類型數據的讀取,並 調用IO流轉換,輸出到磁碟
*
* */
public class DownloadBPMNFile {
public static void main(String[] args) throws IOException {
// 1、創建ProcessEngine流程引擎對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到Repositoryervice實例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、得到查詢器ProcessDefinitionQuery對象
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
// 4、設置查詢條件
processDefinitionQuery.processDefinitionKey("holiday");
// 5、執行查詢操作,得到想要的流程定義
ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
// 6、通過流程定義資訊,得到部署id
String deploymentId = processDefinition.getDeploymentId();
// 7、通過 RepositoryService 的方法,實現讀取圖片資訊以及bpmn文件資訊(輸入流)
// getResourceAsStream(String deploymentId, String resourceName)
// processDefinition.getDiagramResourceName():獲取流程圖片名字
InputStream pngStream = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
// processDefinition.getResourceName():獲取流程bpmn文件名字
InputStream bpmnStream = repositoryService.getResourceAsStream(deploymentId,processDefinition.getResourceName());
// 8、構建輸出流
OutputStream pngOutputStream = new FileOutputStream("C:\\Users\\HongCheng\\Desktop\\holiday\\" + processDefinition.getDiagramResourceName());
OutputStream bpmnOutputStream = new FileOutputStream("C:\\Users\\HongCheng\\Desktop\\holiday\\" + processDefinition.getResourceName());
// 9、轉換輸入流並保存文件
IOUtils.copy(pngStream,pngOutputStream);
IOUtils.copy(bpmnStream,bpmnOutputStream);
// 10、關閉流
pngOutputStream.close();
bpmnOutputStream.close();
pngStream.close();
pngStream.close();
}
}
流程變數
package activiti04;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.runtime.ProcessInstance;
import java.io.Serializable;
import java.util.HashMap;
/**
* 啟動流程實例,流程節點參與人使用UEL表達式 ${變數名} ${變數名.屬性名} ${變數名.方法名()}
* */
public class ActivitiStartInstanceUEL {
public static void main(String[] args) {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到RuntimeService對象
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、設置assignee的值, 流程節點的參與人可以動態選擇
HashMap<String, Object> map = new HashMap<>();
map.put("assignee","zhaoliu");
map.put("user",new User("蘇七","666","suqi"));
// 4、啟動流程實例,同時傳入流程定義的參數值
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday3", map);
// 5、輸出相關資訊
System.out.println(processInstance.getProcessDefinitionName());
}
}
@Getter
@Setter
@AllArgsConstructor
class User implements Serializable {
private String name;
private String id;
private String assignee;
public String getUserAssignee(){
return id + name + assignee;
}
}
流程變數是指在整個流程實例中使用的變數,activiti支援UEL表達式作為流程變數。
UEL表達式有三種寫法: ${變數名} ${變數名.屬性名} ${變數名.方法名()}
另外,流程變數分成全局流程變數和局部流程變數。
流程變數分為:
- 全局global變數,所有節點都可以用。
- 任務節點local變數,僅當前節點可用
全局的流程變數可以通過流程實例來添加,也可以通過任務節點來添加
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(“holiday4”, map);
runtimeService.setVariable(String processInstanceId, String variableName, Object value);
runtimeService.setVariables( String processInstanceId, Map<String, ? extends Object> variables);
taskService.complete(String taskId, Map<String, Object> variables)
taskService.setVariables(String taskId, Map<String, ? extends Object> variables)
taskService.setVariable(String taskId, String variableName, Object value)
局部流程變數:
只能在當前任務節點使用,一旦當前任務節點結束,這個流程變數就會被刪除。
但是歷史表裡面依舊還是會保存我們的局部流程變數,依舊還是可以獲取到。只是當前正在執行的任務不能直接獲取局部流程變數了而已,曲線獲取還是可以的。
局部流程變數的設置:
runtimeService.setVariableLocal(String processInstanceId, String variableName, Object value);
runtimeService.setVariablesLocal( String processInstanceId, Map<String, ? extends Object> variables);
taskService.setVariablesLocal(String taskId, Map<String, ? extends Object> variables)
taskService.setVariableLocal(String taskId, String variableName, Object value)
注意:如果局部變數是加在流程實例上,那依舊還是把所有任務節點共享
下面給一個使用流程變數來確定動態指定任務責任人的例子:




流程變數的使用大致就是這樣子。
我們可以在資料庫act_ru_variable、act_hi_varinst、act_ge_bytearray找到相關資訊



任務監聽器:



任務監聽器是在發生對應的任務相關事件時執行的自定義java邏輯或表達式。
有四種類型的任務監聽器,好像只是用在task 節點上才有用:
- create:任務創建後觸發
- assignment:任務分配後觸發
- complete:任務完成後觸發
- all:所有任務事件都會觸發
監聽器的執行者有四種:
- java類:必須實現org.activiti.engine.delegate.TaskListener這個介面
- Expression 表達式:
- Delegate Expression 表達式:
- script腳本

我們可以在監聽器裡面改變任務處理人,也可以進行其他操作
動態選擇任務節點的處理人:
參考前面流程變數時最後舉得那個例子
簡單的任務分支:


需要用到流程變數,流程變數可以是UEL表達式,但條件必須是boolean類型。
注意:
- 如果UEL表達式中流程變數名不存在會報錯
- 如果UEL表達式中流程變數為空null,流程不按UEL表達式執行,直接流程結束
- 如果UEL表達式都不符合條件,流程結束
- 如果任務連線不設置條件,會走flow序號最小的那天=條路徑
- 這種簡單的分支下,如果多條分支的條件都成立時,會多條分支一起走,會出現問題。所以分支一般用網關
這種分支方式很簡單,但也有一些限制,如果不是很複雜的流程,可以這樣使用,但還是建議使用網關。

flow序號其實就是線的id
任務候選人/任務候選組:
我們之前指定任務都是使用assignee來指定具體哪一個人來執行任務,但是如果這個任務可以有多個執行人,也就是說張三、李四、王五、趙六四個人都可以執行同一個任務,那麼就不能通過assignee來指定了。
此時就可以用candidate user(候選人)來指定一堆執行人,將來這一堆執行人都可以看到這個任務,但是只能有一個人將這個任務領取並執行。多個候選人之間通過逗號隔開
另外也有一個candidate groups(候選組)來指定一個人員組,在這個組裡的人都是候選人,就不用一個個人來指定了。候選組其實也就是一個角色
組任務的辦理流程:
1、指定候選人,或指定候選人組部署流程
2、創建流程實例
3、候選人查詢當前待辦任務
4、候選人領取任務,將組任務變成個人任務
***如果該候選人領取任務後又不想處理了,可以將任務歸還,個人任務變成組任務
5、根據assignee來查詢自己的任務
6、處理任務
taskService.claim(task.getId(),任務負責人);領取任務
taskService.setAssignee(task.getId(),null);放棄任務
taskService.setAssignee(task.getId(),任務負責人);委派任務
在我們正常的業務中,
assignee應該是我們的系統用戶標識,可以是用戶id,也可以是用戶名,反正能唯一區分就行。其意思就是這個任務指定某個人完成,一般都是使用流程變數,動態決定誰可以做。例如我們在用釘釘發起審批時,有時就可以指定給哪個領導審。
candidate user(候選人)應該是多個系統用戶標識,其意思就是這個任務可以是這堆人中的某一個來完成。
candidate groups(候選組)應該是用戶的角色,在正常的系統中,使用角色將用戶進行分組。而我們的實際生活中也是這樣,有領導角色身份的人,才能進行最後的審批決定。
package activiti04.group;
import activiti01.ActivitiDeployment;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.zip.ZipInputStream;
/**
* 組任務
* */
public class ActivitiTaskGroup {
public static void main(String[] args) {
ActivitiTaskGroup activitiTaskGroup = new ActivitiTaskGroup();
activitiTaskGroup.giveUpTask();
}
/**
* 放棄任務。
* 原理:
* 直接將task的assignee設置成null,讓候選人重新搶任務。
* 也可以將任務指定給某個具體的用戶,相當於委派給別人執行
* 注意:
* 如果這個任務不是指定候選組的,那麼當這個人放棄後,將沒有人可以再領取這個任務
*/
@Test
public void giveUpTask() {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到TaskService對象
TaskService taskService = processEngine.getTaskService();
// 3、查詢用戶的組任務
String userId = "hongcheng";
List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("holidayGroup")
.taskAssignee(userId).list();
// 4、放棄任務
for (Task task : taskList) {
System.err.println("流程實例id ==> " + task.getProcessInstanceId());
System.err.println("任務定義key ==> " + task.getTaskDefinitionKey());
System.err.println("任務id ==> " + task.getId());
System.err.println("任務處理人 ==> " + task.getAssignee());
System.err.println("任務名 ==> " + task.getName());
if (userId.equals(task.getAssignee())) {
// 放棄任務
taskService.setAssignee(task.getId(), null);
// 任務委派
// taskService.setAssignee(task.getId(),"hongcheng");
}
System.err.println("任務放棄成功 ==> " + userId);
}
}
/**
* 認領組任務,claim也可以說是對外宣稱任務
* */
@Test
public void claimGroupTaskCandidateUserGroup() {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到TaskService對象
TaskService taskService = processEngine.getTaskService();
// 3、查詢用戶的組任務
String userId = "hongcheng";
List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("holidayGroup")
.taskCandidateGroup("leader").list();
// 4、認領任務
for (Task task : taskList) {
System.err.println("流程實例id ==> "+task.getProcessInstanceId());
System.err.println("任務定義key ==> "+task.getTaskDefinitionKey());
System.err.println("任務id ==> "+task.getId());
System.err.println("任務處理人 ==> "+task.getAssignee());
System.err.println("任務名 ==> "+task.getName());
// 認領任務
taskService.claim(task.getId(),userId);
System.err.println("任務認領成功 ==> "+userId);
}
}
/**
* 查詢組任務,也就是候選人有自己的任務,此時該組任務並沒有真正確定誰是任務的最終負責人assignee
* 按候選人組進行查詢
* */
@Test
public void queryGroupTaskCandidateUserGroup() {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到TaskService對象
TaskService taskService = processEngine.getTaskService();
// 3、查詢用戶的組任務
List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("holidayGroup")
.taskCandidateGroup("leader").list();
// 5、輸出
for (Task task : taskList) {
System.err.println("流程實例id ==> "+task.getProcessInstanceId());
System.err.println("任務定義key ==> "+task.getTaskDefinitionKey());
System.err.println("任務id ==> "+task.getId());
System.err.println("任務處理人 ==> "+task.getAssignee());
System.err.println("任務名 ==> "+task.getName());
}
}
/**
* 認領組任務,claim也可以說是對外宣稱任務
* */
@Test
public void claimGroupTaskCandidateUser() {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到TaskService對象
TaskService taskService = processEngine.getTaskService();
// 3、查詢用戶的組任務
String userId = "wangwu";
List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("holidayGroup")
.taskCandidateUser(userId).list();
// 4、認領任務
for (Task task : taskList) {
System.err.println("流程實例id ==> "+task.getProcessInstanceId());
System.err.println("任務定義key ==> "+task.getTaskDefinitionKey());
System.err.println("任務id ==> "+task.getId());
System.err.println("任務處理人 ==> "+task.getAssignee());
System.err.println("任務名 ==> "+task.getName());
// 認領任務
taskService.claim(task.getId(),userId);
System.err.println("任務認領成功 ==> "+userId);
}
}
/**
* 查詢組任務,也就是候選人有自己的任務,此時該組任務並沒有真正確定誰是任務的最終負責人assignee
* 按候選人列表進行查詢
* */
@Test
public void queryGroupTaskCandidateUser() {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到TaskService對象
TaskService taskService = processEngine.getTaskService();
// 3、查詢用戶的組任務
List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("holidayGroup")
.taskCandidateUser("lisi").list();
// 5、輸出
for (Task task : taskList) {
System.err.println("流程實例id ==> "+task.getProcessInstanceId());
System.err.println("任務定義key ==> "+task.getTaskDefinitionKey());
System.err.println("任務id ==> "+task.getId());
System.err.println("任務處理人 ==> "+task.getAssignee());
System.err.println("任務名 ==> "+task.getName());
}
}
/**
* 完成任務
* */
@Test
public void complete() {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到TaskService對象
TaskService taskService = processEngine.getTaskService();
// 3、結合任務查詢,將查詢到的任務進行處理
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("holidayGroup")
.taskAssignee("zhangsan")
.list();
// 4、完成任務
for (Task task : taskList) {
taskService.complete(task.getId());
System.err.println(task.getName());
}
}
/**
* 查詢自己的個人任務
* */
@Test
public void taskQuery() {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到TaskService對象
TaskService taskService = processEngine.getTaskService();
// 3、用流程定義的key和負責人assignee來實現當前用戶的任務列表查詢
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("holidayGroup").taskAssignee("zhangsan")
.list();
// 4、任務列表查詢
for (Task task : taskList) {
System.err.println("流程實例id ==> "+task.getProcessInstanceId());
System.err.println("任務定義key ==> "+task.getTaskDefinitionKey());
System.err.println("任務id ==> "+task.getId());
System.err.println("任務處理人 ==> "+task.getAssignee());
System.err.println("任務名 ==> "+task.getName());
}
}
/**
* 啟動流程
* */
@Test
public void startInstance() {
// 1、得到processEngine對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到RuntimeService對象
RuntimeService runtimeService = processEngine.getRuntimeService();
// 3、設置assignee的值, 流程節點的參與人可以動態選擇
HashMap<String, Object> map = new HashMap<>();
// 4、啟動流程實例,同時傳入流程定義的參數值
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holidayGroup", map);
// 5、輸出相關資訊
System.out.println(processInstance.getProcessDefinitionName());
System.out.println(processInstance.getId());
}
/**
* 部署流程
* */
@Test
public void deployment() {
// 1、創建ProcessEngine流程引擎對象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、得到Repositoryervice實例
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、獲取壓縮文件
InputStream inputStream = ActivitiDeployment.class.getClassLoader().getResourceAsStream("bpmn/group/holidayGroup.zip");
// 4、創建一個ZipInputStream流
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
// 3、進行部署,bpmn文件是一定要的,圖片文件可以沒有,流程key相同的話,會使用最新部署的流程定義
Deployment deployment = repositoryService.createDeployment()
.addZipInputStream(zipInputStream)
.name("請假申請流程候選人")
.deploy();
// 4、輸出部署的資訊
System.out.println(deployment.getName());
System.out.println(deployment.getId());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="//www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="//www.w3.org/2001/XMLSchema"
xmlns:activiti="//activiti.org/bpmn"
xmlns:bpmndi="//www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="//www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="//www.omg.org/spec/DD/20100524/DI"
typeLanguage="//www.w3.org/2001/XMLSchema"
expressionLanguage="//www.w3.org/1999/XPath"
targetNamespace="//www.activiti.org/test">
<process id="holidayGroup" name="候選人流程" isExecutable="true">
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="usertask1" name="填寫請假申請" activiti:assignee="zhangsan"></userTask>
<sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
<userTask id="usertask2" name="部門經理審核" activiti:candidateUsers="lisi,wangwu"></userTask>
<sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
<userTask id="usertask3" name="總經理審核" activiti:candidateGroups="leader"></userTask>
<sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_holidayGroup">
<bpmndi:BPMNPlane bpmnElement="holidayGroup" id="BPMNPlane_holidayGroup">
<bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
<omgdc:Bounds height="35.0" width="35.0" x="110.0" y="230.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
<omgdc:Bounds height="55.0" width="105.0" x="190.0" y="220.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
<omgdc:Bounds height="55.0" width="105.0" x="340.0" y="220.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
<omgdc:Bounds height="55.0" width="105.0" x="490.0" y="220.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
<omgdc:Bounds height="35.0" width="35.0" x="640.0" y="230.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="145.0" y="247.0"></omgdi:waypoint>
<omgdi:waypoint x="190.0" y="247.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="295.0" y="247.0"></omgdi:waypoint>
<omgdi:waypoint x="340.0" y="247.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
<omgdi:waypoint x="445.0" y="247.0"></omgdi:waypoint>
<omgdi:waypoint x="490.0" y="247.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
<omgdi:waypoint x="595.0" y="247.0"></omgdi:waypoint>
<omgdi:waypoint x="640.0" y="247.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
網關:
網關其實就是控制流程進行分支、匯聚的一個節點
activiti裡面網關有4種:
和簡單任務分支相比就是多個了網關節點,其他東西不變。

排他網關:
- 只會執行一條路徑,如果有多條路徑可以走,那麼默認會走下一個節點的id比較小的那條路徑。可以防止多條分支同時成立,同時走了多條分支。
- 如果沒有一個分支可以走,那就會報錯。
- 必須保證有一條路徑可以走

並行網關:
- 可以作為多條分支匯聚(只有所有匯聚分支都完成,才會進去下一步)。
- 也可以作為多條分支分散,分散分支時沒有條件的,即便你設置了條件,也會被忽略掉,他肯定是全部分支都要執行。

包含網關:
- 同時擁有排他網關和並行網關的特性。也就是說根據條件分散執行條件成立的一個或多個分支,也可以等待一個或多個分支匯聚。
針對上圖,當userType==1時,會同時走常規項目和抽血化驗這兩條路徑,如果userType==2,會走三條路徑
任務定時提醒:
我們實際的流程中,經常會有人一直不審批,所以就需要有一個提醒機制
這個時候我們就需要用到邊界事件。有3篇部落格介紹的挺不錯的,有興趣的自己去看:
//blog.csdn.net/qq_33333654/article/details/101374202
//blog.csdn.net/qq_33333654/article/details/101373157
//www.cnblogs.com/dengjiahai/p/6942310.html

iso 8601格式解析
R2/2015-06-04T19:25:16.828696-07:00/P1DT10S
上面的字元串通過”/”分為了三部分即:
重複次數/開始時間/運行間隔
重複次數
- R – 將永遠重複
- R1 – 將重複一次
- R231 – 將重複231次。
開始時間
任務第一次運行的時間。如果開始日期時間已經過去,將返回一個錯誤。
其中”T”用來分割日期和時間,時間後面跟著的”-07:00″表示西七區,注意”-“是連字元,不是減號。
時區默認是0時區,可以用”Z”表示,也可以不寫。
對於中國,要使用”+08:00″,表示東八區。
上面的字元串表示 2015年6月4日,19點25分16秒828696納秒,西七區。
運行間隔
運行間隔以”P”開始,和上面一樣也是用”T”分割日期和時間,如P1Y2M10DT2H30M15S
- P 開始標記
- 1Y – 一年
- 2M – 兩個月
- 10D – 十天
- T – 時間和日期分的割標記
- 2H – 兩個小時
- 30M – 三十分鐘
- 15S 十五秒鐘
例子,注意如果沒有年月日,”T”也不能省略
- P1DT1M – 一天一分鐘執行一次
- P1W – 一周執行一次
- PT1H – 一小時執行一次
- PT10S – 十秒執行一次
Time duration:延遲時間,使用「運行間隔」的格式,例如:PT1M30S,一分30秒後執行。
Time date:可以是java.util.Date的變數,也可以是符合ISO 8601 的一個時間點字元串
Time cycle:格式:「循環次數/執行間隔」,例如:R3/P1DT3H,循環執行3次,每次間隔1天3小時。這裡也可以使用cron表達式。
cancel activiti:是否取消當前節點任務,true表示只要超時了,就取消這個當前節點任務。
原理:activiti會在act_ru_timer_job表增加一條記錄,到指定的時間時,會讀取這條記錄,同時判斷這個任務完成沒有,如果沒有完成,就會執行TimerBoundaryEvent連著的下一個任務。如果制定了要取消當前任務,就會把當前任務取消。
注意:想要啟動定時器,加上這段配置
注意:想要啟動定時器,加上這段配置
Service Task服務任務:
之前我們都是使用user task,那這兩者有啥區別呢?
user task是我們的用戶自定義任務,需要我們自己來手動完成
但是service task是服務任務,只要進入了這個任務,系統就會自動執行,不需要我們手動執行。
我們上個例子就用了service task來做循環提醒


需要注意的是,你得實現
org.activiti.engine.delegate.JavaDelegate這個介面
流程駁回:
我們的實際中的流程經常會被打回,這種情況下我個建議使用排他網關進行分支。當然,網上也有其他的方式進行撤回,但我還是感覺這樣子更簡單點
