该章节注意介绍一下,基于camunda封装的流程相关的一下操作接口,这里每一个流程实例都通过Businesskey 字段与实际的业务单据进行了绑定,每条送审的单据对应了一条流程实例。在此基础上进行了接口的封装,包括接口有:送审接口、审核接口、驳回接口、销审接口、日志查询等接口的封装。
直接上代码
//创建流程实例
@Override
public PROCINST startProcessInstanceByDefKey(String processDefKey, String business, String initiator) {
HashMap<String, Object> variable = new HashMap<>();
variable.put("initiator", initiator);
identityService.setAuthenticatedUserId(initiator); //ACT_HI_PROCINST.START_USER_ID字段的赋值-开始节点人
ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefKey, business, variable);
PROCINST procinst = procinst = new PROCINST(instance.getProcessDefinitionId(), instance.getProcessInstanceId(), instance.getBusinessKey(), instance.isSuspended(), instance.isEnded());
return procinst;
}
参数介绍
processDefKey:这里首先需要传入的是流程定义模板的key,前提是我们之前已经部署了相应的流程模板。
businessKey:这是流程实例的业务标识Key,需要用该字段与我们的业务单据进行绑定,该字段可以通过
UUID.randomUUID().toString()来自定生成。
initiator:启动流程实例时的操作人,这里可以理解为制单人,或者是送审人,但是需要注意,在实际应用场景中,我们的制单人不一定就是单据送审人。
如此操作,就会创建出一条流程实例。
送审操作指的:制单人,也就是流程启动的第一节点受理人,需要他将单据推送出去,然后后续由流程上的相关负责人在进行审核。这里的送审,其实就是相当于审核操作,只是由制单人进行审核,自己审核自己的单据,所有流程控制中也被称为送审操作。
我这里送审操作和审核操作在CamundaServer层都是调用的同一个封装接口。
//送审/审核操作
@Override
public String submitProcessInstance(String businessKey, String initiator, String comment) {
String resultString = "";
Task task = queryTaskByBusinessKey(businessKey, initiator);
if (ObjectUtil.isNull(task)) {
resultString = "没有查询到对应的单据流程";
} else if (!task.getAssignee().equalsIgnoreCase(initiator)) {
resultString = "没有审核权限!";
} else {
String taskId = task.getId();
System.out.println("taskId = " + taskId);
Comment comment1 = taskService.createComment(taskId, task.getProcessInstanceId(), comment);
System.out.println("comment1 = " + comment1);
taskService.complete(taskId);
resultString = "审核成功!";
}
return resultString;
}
/**
* 根据业务标识代码获取当前节点
*
* */
private Task queryTaskByBusinessKey(String businessKey, String initiator) {
Task task = null;
ProcessInstance instance = runtimeService.createProcessInstanceQuery()
.processInstanceBusinessKey(businessKey)
.singleResult();
if (ObjectUtil.isNull(instance)) return null;
List list = taskService.createTaskQuery()
.processInstanceId(instance.getProcessInstanceId())
.active() //正在运行时的节点?
.list();
if (list.size() == 1) task = list.get(0);
else {
task = taskService.createTaskQuery()
.processInstanceId(instance.getProcessInstanceId())
.active()
.taskAssignee(initiator)
.singleResult();
}
return task;
}
这里单独封装了一个通过业务标识(BUSINESSKEY)和 受理人(制单人 initiator/assignee) 来查询对应应该程中当前正在运行时节点的接口queryTaskByBusinessKey。
其中需要注意的是,里面有个if判断操作的作用是:在存在会签节点的时候,同一个节点,会出现多个审核人activity任务活动,且act_Id都是相同的,所有需要加入受理人assignee/initiator来进行筛选出对应需要查找的任务活动节点!
在提交审核任务的接口 submitProcessInstance 中 businessKey指业务标识代码、comment指提交意见、initiator指当前操作人员。
在进行送审操作之前,首先是通过businessKey、initiator进行判断当前送审人是否具有审核权限。在确认含有权限之后,在进行送审操作。
送审操作首先是需要通过 taskService.createComment(taskId,processInstanceId, comment) 来创建一个意见对象,同时绑定了taskId,这样在提交任务时该节点对应的审核意见等信息会持久化到 ACT_HI_COMMENT 表中,然后在通过 taskService.complete(taskId); 对任务进行提交即可。
**注:**正常情况下我们还需要在审核任务的操作接口中为下一个节点设置审核人,
即:taskService.setAssignee(userId) 或者是通过 taskService.setVariable()的方式为流程模板中定义好的参数表达式${xxx}赋值,但是我这里封装的流程中这几部分操作全部通过节点上的 监听器Listeners 进行提前处理了,所有在 送审/审核 操作中就没有在去单独设置。监听器的设置方式在 :
springboot集成Camunda审核流程(二):Camunda Modeler设计器设置BPMN流程
这里直接将查询我创建的单据List、查询我代办的任务节点、查询我已审核的任务节点 三种类型的接口归类在一起进行分享了。
这里查询的是制单人 A 创建出来的所有单据,也就是查询当前操作人为流程中第一个任务节点的受理人的所有流程单据,在实际场景中就是制单人的单据。
//查询我创建的流程
@Override
public List<String> queryMySalaryProcess(String initiator) {
/* 迭代【可添加更多种条件查询】:时间范围、内置分页查询等! */
List<HistoricProcessInstance> list = list = historyService.createHistoricProcessInstanceQuery()
//通过制单人来查询流程中的数据
.startedBy(initiator)
.list();
if (CollUtil.isEmpty(list)){
return null;
}
ArrayList<String> businessKeyList = new ArrayList<>();
list.forEach(procInst -> {
businessKeyList.add(procInst.getBusinessKey());
});
return businessKeyList;
}
参数initiator(制单人/当前操作人)。这里只是查询出了对应单据的业务标识 BusinessKey,后续也会通过这个业务标识根据业务需求 在去对应的业务单据表中查询出对应单据的数据。
同时还可以根据时间需求添加一些查询条件,camunda中的查询接口自己也内置了分页查询的功能,这里我没有采用,可以根据自己需求进行调整。
查询代办任务就是指 当前业务审核流程中 待审核节点中的assignee受理人为 ‘操作员A’ ,那么这条单据就是 ‘操作员A’ 的待审核单据,已办任务顾名思义指示 当前操作员已经审核过的任务节点。
这里查询代办任务 和 已办任务封装在同一个接口中的,查询时通过参数来区分调用的哪一个接口。同样是采用了只查询业务单据标识BusinessKey,后续通过这个业务标识BusinessKey来对应获取到每一条单据的详细信息。
/**
* 查询已办/未办 单据
* */
@Override
public List queryMyTodoTask(String userId, String type) {
ArrayList<Object> businessList = new ArrayList<>();
//查询代办
if (type.equalsIgnoreCase("0")) {
List<Task> tasks = taskService.createTaskQuery()
.taskAssignee(userId)
.active()
// .listPage() 【可分页查询】
.list();
if (CollUtil.isEmpty(tasks)){
return null;
}
tasks.forEach(task -> {
//为查询到相关单据
String businessKey = historyService.createHistoricProcessInstanceQuery()
// .orderByProcessInstanceStartTime() 【可添加时间查询范围】
// .orderByProcessInstanceEndTime()
.processInstanceId(task.getProcessInstanceId())
.singleResult()
.getBusinessKey();
businessList.add(businessKey);
});
}
//查询已办
else if (type.equalsIgnoreCase("1")) {
List<HistoricTaskInstance> completedTaskList = historyService.createHistoricTaskInstanceQuery()
.taskAssignee(userId)
.finished()
.taskDeleteReason("completed")
.list();
if (CollUtil.isEmpty(completedTaskList)){
//为查询到相关单据
return null;
}
completedTaskList.forEach(taskOld ->{
String businessKey = historyService.createHistoricProcessInstanceQuery()
// .orderByProcessInstanceStartTime() 【可添加时间查询范围】
// .orderByProcessInstanceEndTime()
.processInstanceId(taskOld.getProcessInstanceId())
.singleResult()
.getBusinessKey();
businessList.add(businessKey);
});
}
return businessList;
}
正常情况下,任务节点的审核过程都是按照流程定义模板中的过程一步一步进行下去的,但是在实际环境需求中,有时候任务流程中的单据某些东西不符合规定,就需要重新打回起点或者其他节点,让单据重启调整后在继续走流程,这个流程节点往回迁移的过程就是驳回。
在驳回操作中涉及到下面几种类型,分别进行介绍:驳回第一任,驳回上一任,驳回任一任。这三种类型在代码层面上都是类型的操作,只是我们选择的目标节点不同。
在驳回操作中,最核心的API就是如下:
runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
// .cancelActivityInstance(getInstanceIdForActivity(tree,task.getTaskDefinitionKey())) //关闭当前节点相关的任务
.cancelAllForActivity(task.getTaskDefinitionKey())
//暂时不清楚该内容提交到何处!
.setAnnotation(“进行了驳回到第一任务节点操作!”)
//启动目标活动节点
.startBeforeActivity(toActId)
.setVariables(taskVariable)
.execute();
该API接口就是将我们的流程中的运行时间点进行任意的修改调整,可以指定跳转到某一任务节点,同时能取消掉对应的需要取消的代办节点。
/**
*驳回操作
* */
@Override
public String turnTask(String userId, String businessKey, String type, String comment) {
Task task = queryTaskByBusinessKey(businessKey, userId);
if (ObjectUtil.isNull(task)){
String result = new String("未查询到对应的审核单据!");
return new String("未查询到对应的审核单据!");
}
if (!task.getAssignee().equalsIgnoreCase(userId)){
return new String("没用审核权限!");
}
//获取所有已办节点
List<HistoricActivityInstance> userTaskList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(task.getProcessInstanceId())
//用户类型节点
.activityType("userTask")
.finished() //已经完成的节点
.orderByHistoricActivityInstanceEndTime()
.asc()
.list();
//流程实例的活动实例树
/* ActivityInstance tree = runtimeService.getActivityInstance(task.getProcessInstanceId()); */
if (userTaskList == null || CollUtil.isEmpty(userTaskList)){
return new String("当前任务无法驳回!");
}
switch (type){
//驳回第一任制单人
case "1":{
// TODO: 2023-10-30 1.驳回提交已经无 ok2.驳回第一任还是驳回的上一任 3.会签节点上的驳回操作出现只结束了当前任务的驳回!
if (userTaskList.size()<2){
return new String("第一个用户节点无法驳回!");
}
HistoricActivityInstance historicActivityInstance = userTaskList.get(0);
String toActId = historicActivityInstance.getActivityId();
String assignee = historicActivityInstance.getAssignee();
//设置流程可变参数
HashMap<String, Object> taskVariable = new HashMap<>();
taskVariable.put("assignee",assignee);
//流程审核+驳回
//任务流程创建了提交模板Comment 但是没有提交 taskService.complete(taskId)。--所有节点也不会提交到后台去
taskService.createComment(task.getId(),task.getProcessInstanceId(),"驳回原因:"+comment);
//任务流程实例修改位置
runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
// .cancelActivityInstance(getInstanceIdForActivity(tree,task.getTaskDefinitionKey())) //关闭当前节点相关的任务
.cancelAllForActivity(task.getTaskDefinitionKey())
//暂时不清楚该内容提交到何处!
.setAnnotation("进行了驳回到第一任务节点操作!")
//启动目标活动节点
.startBeforeActivity(toActId)
.setVariables(taskVariable)
.execute();
return new String("驳回到制单人成功!");
}
//驳回上一任
case "2":{
//判断当前节点是否为第一个节点
HistoricActivityInstance historicActivityInstance = userTaskList.get(0);
String activityId = historicActivityInstance.getActivityId();
if(activityId.equals(task.getTaskDefinitionKey())) {
return new String("第一节点无法驳回!");
}
//获取上一个节点
Map<String, String> lastNode = getLastNode(userTaskList, task.getTaskDefinitionKey());
if (ObjectUtil.isNull(lastNode)) {
return new String("退回节点异常!");
}
String toActId = lastNode.get("toActId");
String assignee = lastNode.get("assignee");
//设置流程中的可变参数
HashMap<String, Object> taskVariable = new HashMap<>(2);
taskVariable.put("user",assignee);
//进行驳回操作
taskService.createComment(task.getId(),task.getProcessInstanceId(),"驳回:"+comment);
runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
//.cancelActivityInstance(getInstanceIdForActivity(tree,task.getTaskDefinitionKey())) //关闭相关任务!(当前节点就会被删除。但是之前审核过的节点还是会存在!)
//该方式关闭所有activityId相同的activity活动都会被取消暂停(会签节点)
.cancelAllForActivity(task.getTaskDefinitionKey())
.setAnnotation("进行驳回到上一任务节点操作!")
//启动目标活动节点
.startBeforeActivity(toActId)
//流程可变参数赋值
.setVariables(taskVariable)
.execute();
return new String("驳回上一任成功!");
}
//驳回任一任
case "3":{
//
}
default:{
}
}
return null;
}
参数介绍:
userId 当前操作员Id:主要是为了进行一些权限的判定操作,调用了之前封装的queryTaskByBusinessKey()方法,进行权限的校验
businessKey 业务标识代码:这样已该字段为主键,查询出对应需要调整的单据
type:操作类型的判断,主要涉及到 驳回到第一岗、驳回到制单人两个操作,驳回到任意岗位需要后续进行 特殊处理,所有就没有在这里进行封装。
comment:驳回节点的审核意见。
历史已审核节点查询
在进行驳回操作之前首先是需要通过 historyService.createHistoricActivityInstanceQuery() 来查询获取到对应任务节点的所有历史已办节点,这样在进行驳回操作时才能选取驳回的目标节点,同时还需要通过历史节点List来进行一些特殊情况的判断:是否为第一个节点、或者没有查询到相关单据等!
驳回到第一任操作
在驳回到第一任操作中,首先都是判断节点是否为第一个任务节点。然后就通过上一步查询到的历史已审核节点集合中,获取出第一个节点get(0),该节点就是第一个任务节点,也是驳回到第一任的目标节点,然后获取该节点中的 Assignee 受理人、ActId 任务活动Id 等参数后,调用核心API:createProcessInstanceModification即可完成节点的跳转驳回操作。
驳回到上一任操作
同理的我们需要通过上一步获取到的历史已办任务节点集合List,进行相应的一些合理性判断。然后在通过该集合获取当前流程运行时节点的上一个任务节点信息,然后同样在调用核心接口进行节点的修改。
这里从历史已审核集合中获取上一任节点的操作是单独封装了一个查询接口:
private Map<String,String> getLastNode(List<HistoricActivityInstance> resultList,String currentActivityId){
HashMap<String, String> backNode = new HashMap<>();
//新建一个有序不重复集合
LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
for (HistoricActivityInstance his: resultList){
linkedHashMap.put(his.getActivityId(),his.getAssignee());
}
int originSize = resultList.size();
//判断历史节点中是否已经存在过当前节点
boolean flag = false;
for (Map.Entry entry:linkedHashMap.entrySet()){
if (currentActivityId.equalsIgnoreCase((String) entry.getKey())){
flag = true;
break;
}
}
//当前节点不在历史节点里面,最后一个节点是完成节点
if (!flag){
HistoricActivityInstance historicActivityInstance = resultList.get(originSize - 1);
backNode.put("toActId",historicActivityInstance.getActivityId());
backNode.put("assignee",historicActivityInstance.getAssignee());
return backNode;
//当前节点在历史节点中(已经退回过)
}else {
ListIterator<Map.Entry<String, String>> li = new ArrayList<>(linkedHashMap.entrySet()).listIterator();
while (li.hasNext()){
Map.Entry<String, String> entry = li.next();
if (currentActivityId.equalsIgnoreCase(entry.getKey())){
//光标上一到当前节点
li.previous();
//当前相同节点的上一节点
Map.Entry<String, String> previous = li.previous();
backNode.put("toActId",previous.getKey());
backNode.put("assignee",previous.getValue());
return backNode;
}
}
}
return null;
}
**注:**在对流程实例进行驳回操作时,即调用API:createProcessInstanceModification对流程运行时节点进行调整时,我这之前我们都可以通过 taskService.createComment(task.getId(),task.getProcessInstanceId(),“驳回原因:”+comment) 该接口为原当前运行任务节点添加一个意见评论日志对象,这样在查询日志操作时,我也能通过ACT_HI_COMMENT 数据表中持久化的数据得到完整的流程审核过程。
销审操作涉及到的操作权限判断,我的思路是:通过 业务标识BusinessKey 查询对应流程实例,然后在获取到该流程实例正在运行时节点、运行时节点的上一节点,在通过上一节点的审核人信息与当前操作人的信息对比判断是否具有销审权限。
在销审权限确定之后,在通过上面介绍的流程运行时节点修改 API:createProcessInstanceModification 进行修改流程的运行节点位置即可。
/**
*@Description--节点的销审操作!
*@Param [businessKey, userId, comment]
*@return java.lang.String
*/
@Override
public String revocationTask(String businessKey, String userId, String comment) {
//查询当前运行时节点
ProcessInstance instance = runtimeService.createProcessInstanceQuery()
.processInstanceBusinessKey(businessKey)
.singleResult();
if (ObjectUtil.isNull(instance)) {
return "未查询到相关单据信息!";
}
List<Task> list = taskService.createTaskQuery()
.processInstanceId(instance.getProcessInstanceId())
.active() //正在运行时的节点?
.list();
Task task = list.get(0);
//查询历史审核节点
LinkedHashMap<String,Map> taskList =(LinkedHashMap<String, Map>) queryOldTaskList(businessKey);
if (ObjectUtil.isNull(taskList)) {
return "没有销审权限!";
}
int size = taskList.size();
//todo : size-1????
String taskListKey =(String) taskList.keySet().toArray()[size-1];
Map map = taskList.get(taskListKey);
String act_assignee =(String) map.get("act_Assignee");
String act_id = (String) map.get("act_Id");
if (! act_assignee.equalsIgnoreCase(userId)) {
return "您没有权限销审当前单据!";
}else {
taskService.createComment(task.getId(),task.getProcessInstanceId(), "销审:" + comment);
HashMap<String,Object> taskVariable = new HashMap<>();
taskVariable.put("assignee",act_assignee);
runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
.cancelAllForActivity(task.getTaskDefinitionKey())
.setAnnotation("销审回撤到上一节点!")
.startBeforeActivity(act_id)
.setVariables(taskVariable)
.execute();
}
return "销审成功!";
}
/** 查询已经审核过的节点[1.驳回任一节点时使用 2.被驳回后的送审操作*/
@Override
public Object queryOldTaskList(String businessKey) {
HistoricProcessInstance historicProcessInstance = queryProcessInstanceByBusinessKey(businessKey);
if (ObjectUtil.isNull(historicProcessInstance)) {
return "未查询到相关单据!";}
List<HistoricActivityInstance> userTask = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(historicProcessInstance.getId())
.activityType("userTask")
.finished()
.orderByHistoricActivityInstanceEndTime()
.asc()
.list();
LinkedHashMap<String,Map> taskLink = new LinkedHashMap<>();
userTask.stream().forEach(new Consumer<HistoricActivityInstance>(){
@Override
public void accept(HistoricActivityInstance historicActivityInstance) {
String activityName = historicActivityInstance.getActivityName();
if (taskLink.containsKey(activityName)){
return;
}
else {
HashMap<String, String> map = new HashMap<>();
map.put("act_Id",historicActivityInstance.getActivityId());
map.put("act_Assignee",historicActivityInstance.getAssignee());
taskLink.put(historicActivityInstance.getActivityName(),map);
}
}
});
return taskLink;
}
越级送审操作是我在实际情况中遇到的一种特殊业务需求,这里也简单的介绍一下。 就是在单据被驳回到制单人(第一任)后,制单人再次进行送审时,不需要在按照原流程模板在依次逐一进行送审操作。在单据进行重新调整修改符合要求之后,能直接送审到上一次驳回节点处,直接跳过前面几个之前已经审核通过的节点。
这里指定审核目标送审,其中的核心API:createProcessInstanceModification 调用的也是之前介绍的,对流程实例中运行时节点的修改。
/** 被驳回后的节点,送审到目标指定节点 */
@Override
public String submitProcessInstanceToTargetActivity(String businessKey,String userId, String toActivity, String assignee,String commit) {
Task task = queryTaskByBusinessKey(businessKey, userId);
if (ObjectUtil.isNull(task)) {
return new String("未查询到对应的审核单据!");
}
if (!task.getAssignee().equalsIgnoreCase(userId)){
return new String("没用审核权限!");
}
//获取所有已办节点
taskService.createComment(task.getId(),task.getProcessInstanceId(),commit);
HashMap<String,Object> taskVariable = new HashMap<>();
taskVariable.put("assignee",assignee);
runtimeService.createProcessInstanceModification(task.getProcessInstanceId())
.cancelAllForActivity(task.getTaskDefinitionKey())
.setAnnotation("越级送审操作!")
.startBeforeActivity(toActivity)
.setVariables(taskVariable)
.execute();
return "越级送审成功!";
}
参数:
businessKey 单据业务标识
userId 当前操作员Id
toActivity 送审目标节点的ACT_ID
assignee 目标节点的审核人/受理人
commit 节点提交意见信息
目标节点的查询方式
在驳回任意岗位接口,已经这个越级送审接口时, 我们都需要提前选择好某一个目标节点的信息,所以这里封装了这个历史节点信息的查询接口!
该接口的作用是:通过也不标识BusinessKey ,查询流程实例中,已经审核过的节点任务。然后通过我我们的实际需求选择目标节点。
/** 查询已经审核过的节点[1.驳回任一节点时使用 2.被驳回后的送审操作*/
@Override
public Object queryOldTaskList(String businessKey) {
HistoricProcessInstance historicProcessInstance = queryProcessInstanceByBusinessKey(businessKey);
if (ObjectUtil.isNull(historicProcessInstance)) {
return "未查询到相关单据!";}
List<HistoricActivityInstance> userTask = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(historicProcessInstance.getId())
.activityType("userTask")
.finished()
.orderByHistoricActivityInstanceEndTime()
.asc()
.list();
LinkedHashMap<String,Map> taskLink = new LinkedHashMap<>();
userTask.stream().forEach(new Consumer<HistoricActivityInstance>(){
@Override
public void accept(HistoricActivityInstance historicActivityInstance) {
String activityName = historicActivityInstance.getActivityName();
if (taskLink.containsKey(activityName)){
return;
}
else {
HashMap<String, String> map = new HashMap<>();
map.put("act_Id",historicActivityInstance.getActivityId());
map.put("act_Assignee",historicActivityInstance.getAssignee());
taskLink.put(historicActivityInstance.getActivityName(),map);
}
}
});
return taskLink;
}
响应示例:
日志查询的接口就不多介绍了,就是一些需要的数据,从任务节点对象中获取出来封装后就即可,这里参数就是通过业务单据的业务标识BusinessKey来获取相应单据的审核日志信息。
//审核日志查询
/**
* [注:日志顺序 1开始时间 相同顺延 2排列结束时间]
* activityType:节点类型 null就不显示
* taskId:taskId相同的为会签节点
* state:completed审核完成 deleted驳回 null待审核
* */
@Override
public List queryProcessLog(String businessKey) {
String processInstanceId = historyService.createHistoricProcessInstanceQuery()
.processInstanceBusinessKey(businessKey)
.singleResult()
.getRootProcessInstanceId();
List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.orderByHistoricActivityInstanceStartTime() //这里开始时间相同的可以,只能前端在根据结束时间继续排序
.asc()
.list();
List<Map<String,Object>> result=new ArrayList<>(list.size());
System.out.println(list.size());
for (HistoricActivityInstance historicActivityInstance : list) {
Map<String,Object> map=new HashMap<>();
String taskId = historicActivityInstance.getTaskId();
List<Comment> taskComments = taskService.getTaskComments(taskId);
System.out.println("taskId = " + taskId);
System.out.println(taskComments.size());
map.put("activityName",historicActivityInstance.getActivityName());
System.out.println("historicActivityInstance.getActivityType() = " + historicActivityInstance.getActivityType());
map.put("activityType",matching(historicActivityInstance.getActivityType()));
map.put("assignee",historicActivityInstance.getAssignee()==null?"无":historicActivityInstance.getAssignee());
map.put("taskId",historicActivityInstance.getTaskId());
map.put("act_Id",historicActivityInstance.getActivityId());
/*加入activity状态字段*/
if (taskId != null) {
map.put("state",historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult().getDeleteReason());
}
Date startTime = historicActivityInstance.getStartTime();
if (ObjectUtil.isNull(startTime)){
map.put("starTime","");
}
else{
map.put("startTime", DateFormatUtils.format(historicActivityInstance.getStartTime(),"yyyy-MM-dd HH:mm:ss") );
}
Date endTime = historicActivityInstance.getEndTime();
if (ObjectUtil.isNull(endTime)){
map.put("endTime","");
map.put("costTime","");
}else {
map.put("endTime",DateFormatUtils.format(historicActivityInstance.getEndTime(),"yyyy-MM-dd HH:mm:ss"));
map.put("costTime",getDatePoor(historicActivityInstance.getEndTime(),historicActivityInstance.getStartTime()));
}
if (taskComments.size()>0){
map.put("message",taskComments.get(0).getFullMessage());
}else {
map.put("message","无");
}
result.add(map);
}
System.out.println("result = " + result);
return result;
}
/** 时间差计算 */
public String getDatePoor(Date endDate, Date nowDate) {
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
long ns = 1000;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime();
// 计算差多少天
long day = diff / nd;
// 计算差多少小时
long hour = diff % nd / nh;
// 计算差多少分钟
long min = diff % nd % nh / nm;
// 计算差多少秒//输出结果
long sec = diff % nd % nh % nm / ns;
return day + "天" + hour + "小时" + min + "分钟"+ sec + "秒";
}
/** 日志log类型替换 */
private String matching(String ActivityType){
String value="";
switch (ActivityType){
case "startEvent":
value="流程开始";
break;
case "userTask":
value="用户处理";
break;
case "noneEndEvent":
value="流程结束";
break;
default:
value="未知节点";
break;
}
return value;
}
日志查询结果实例:
**最后,大家觉得有什么需要补充或不足的地方欢迎留言!! **