package com.yussion;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.activiti.engine.HistoryService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
public class RollBackTaskTest {
public static void main(String[] args) throws ParseException {
excuteTask();
rollBackTask2("9"); //taskId 剛完成的任務ID,即需要回退的任務對應任務ID
rollBackTask("15"); //taskId 目前任務ID,即需要回退的任務ID的下一步任務ID
}
private static void excuteTask() throws ParseException {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
//.setJdbcUrl("jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000").setJdbcUsername("sa").setJdbcPassword("")
//.setJdbcDriver("org.h2.Driver")
.setJdbcUrl("jdbc:mysql://localhost:3306/activiti?serverTimezone=UTC").setJdbcUsername("root").setJdbcPassword("123456")
.setJdbcDriver("com.mysql.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
ProcessEngine processEngine = cfg.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment().addClasspathResource("onboarding.bpmn20.xml")
.deploy();
repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("onboarding");
//startOnboarding - enterOnboardingData - personalizedIntro - endOnboarding
//執行完成enterOnboardingData後,需要回退該已完成的任務,此處構造出enterOnboardingData任務完成的資料
if (processInstance != null && !processInstance.isEnded()) {
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();
Task task = tasks.get(0);
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("fullName", "張三");
variables.put("yearsOfExperience", 11);
taskService.complete(task.getId(), variables);
//variables.clear();
//variables.put("personalWelcomeTime", "1/1/2021");
//task = tasks.get(1);
//taskService.complete(task.getId(), variables);
}
}
//lastHiTaskId: 剛完成的任務ID,即需要回退的任務對應任務ID
private static void rollBackTask2(String lastHiTaskId) {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
//.setJdbcUrl("jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000").setJdbcUsername("sa").setJdbcPassword("")
//.setJdbcDriver("org.h2.Driver")
.setJdbcUrl("jdbc:mysql://localhost:3306/activiti?serverTimezone=UTC").setJdbcUsername("root").setJdbcPassword("123456")
.setJdbcDriver("com.mysql.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
ProcessEngine processEngine = cfg.buildProcessEngine();
// https://www.itdaan.com/blog/2017/10/26/a24659ba5fa8e821ce9bc9267ca96107.html
// 按照完成時間排序取第一個, 即需要回退到該節點
HistoricTaskInstance hstTask = processEngine.getHistoryService().createHistoricTaskInstanceQuery()
.taskId(lastHiTaskId).singleResult();
List<HistoricTaskInstance> htiList = processEngine.getHistoryService().createHistoricTaskInstanceQuery()
.processInstanceId(hstTask.getProcessInstanceId()).finished().orderByTaskCreateTime().desc().list();
if (htiList == null || htiList.size() < 2) {
//回退到開始節點,這種情況清空hi和RU表資料即可
return;
}
String lastTaskId = htiList.get(0).getId(); // 從taskId對應節點回退到parentTaskId對應節點
String execId = hstTask.getExecutionId();
System.out.println(lastTaskId+" "+execId);
}
// taskId 目前任務ID,即需要回退的任務ID的下一步任務ID, 以完成enterOnboardingData後需要回退enterOnboardingData為例 目前任務ID為15,上一步任務ID為9, execId為6
private static void rollBackTask(String taskId) {
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
//.setJdbcUrl("jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000").setJdbcUsername("sa").setJdbcPassword("")
//.setJdbcDriver("org.h2.Driver")
.setJdbcUrl("jdbc:mysql://localhost:3306/activiti?serverTimezone=UTC").setJdbcUsername("root").setJdbcPassword("123456")
.setJdbcDriver("com.mysql.jdbc.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
ProcessEngine processEngine = cfg.buildProcessEngine();
// https://www.itdaan.com/blog/2017/10/26/a24659ba5fa8e821ce9bc9267ca96107.html
// 按照完成時間排序取第一個, 即需要回退到該節點
HistoricTaskInstance hstTask = processEngine.getHistoryService().createHistoricTaskInstanceQuery()
.taskId(taskId).singleResult();
List<HistoricTaskInstance> htiList = processEngine.getHistoryService().createHistoricTaskInstanceQuery()
.processInstanceId(hstTask.getProcessInstanceId()).finished().orderByTaskCreateTime().desc().list();
if (htiList == null || htiList.size() < 2) {
//回退到開始節點,這種情況清空hi和RU表資料即可
return;
}
String lastTaskId = htiList.get(0).getId(); // 從taskId對應節點回退到parentTaskId對應節點
String execId = hstTask.getExecutionId();
System.out.println(lastTaskId+" "+execId);
// 删除待回退的曆史任務
// DELETE from ACT_HI_TASKINST where EXECUTION_ID_=#{execId} and ID_=#{taskId}
// DELETE from ACT_HI_TASKINST where EXECUTION_ID_='6' and ID_='15';
// 更新跳轉任務的完成時間 和狀态
// update ACT_HI_TASKINST set END_TIME_=NULL,DURATION_=NULL,DELETE_REASON_=NULL where EXECUTION_ID_=#{execId} and id_=#{lastTaskId}
// update ACT_HI_TASKINST set END_TIME_=NULL,DURATION_=NULL,DELETE_REASON_=NULL where EXECUTION_ID_='6' and id_='9';
// 更新taskId 解除關聯 ACT_RU_IDENTITYLINK
// String linkId: select ID_ from ACT_RU_IDENTITYLINK where TASK_ID_=#{taskId} select ID_ from ACT_RU_IDENTITYLINK where TASK_ID_='15' -> 16
// update ACT_RU_IDENTITYLINK set TASK_ID_=NULL where ID_=#{linkId} update ACT_RU_IDENTITYLINK set TASK_ID_=NULL where ID_='16'
// 更新目前任務 名稱 fromKey id
// 更新ACT_RU_IDENTITYLINK 的taskid
// update ACT_RU_IDENTITYLINK set TASK_ID_=#{lastTaskId} where ID_=#{linkId} update ACT_RU_IDENTITYLINK set TASK_ID_='9' where ID_='16'
// 更新execu的 act_id_
// UPDATE ACT_RU_EXECUTION a, ( SELECT TASK_DEF_KEY_ FROM ACT_RU_TASK WHERE ID_ = #{lastTaskId} ) b SET a.ACT_ID_ = b.TASK_DEF_KEY_ WHERE ID_ = #{execId}
// UPDATE ACT_RU_EXECUTION a, ( SELECT TASK_DEF_KEY_ FROM ACT_RU_TASK WHERE ID_ = '9' ) b SET a.ACT_ID_ = b.TASK_DEF_KEY_ WHERE ID_ = '6'
}
}
-----------------流程各階段資料庫表資料變化----------------------
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLxEFVOFzZU50MFpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2QjM4EDOzMjMzITNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)