Appearance
createHistoricTaskInstanceQuery
Flowable 7.1.0 摘要:创建历史任务实例查询对象,用于查询已完成或删除的任务历史数据。
方法签名与说明
HistoricTaskInstanceQuery createHistoricTaskInstanceQuery()
创建历史任务实例查询构建器。可以查询所有任务的历史记录,包括已完成、已删除的任务,以及当前正在执行的任务。
Returns:
- HistoricTaskInstanceQuery - 历史任务实例查询构建器
常见使用场景
1. 用户任务历史记录
查询用户处理过的所有任务,用于工作量统计和绩效考核。
2. 任务执行效率分析
分析任务的平均处理时长,找出效率瓶颈。
3. 审批链路追溯
追溯某个业务单据的完整审批过程,查看每个环节的处理人和处理时间。
4. 超时任务监控
查找处理超时的任务,进行预警和催办。
Kotlin + Spring Boot 调用示例
示例1:查询用户处理过的任务
kotlin
import org.flowable.engine.HistoryService
import org.springframework.stereotype.Service
import java.util.Date
data class UserTaskHistory(
val taskId: String,
val taskName: String,
val processName: String,
val startTime: Date,
val endTime: Date?,
val duration: Long?,
val assignee: String?
)
@Service
class UserTaskHistoryService(
private val historyService: HistoryService
) {
/**
* 查询用户处理过的所有任务
* 企业场景:员工个人工作台,查看历史任务记录
*/
fun getUserTaskHistory(userId: String): List<UserTaskHistory> {
val historicTasks = historyService.createHistoricTaskInstanceQuery()
.taskAssignee(userId)
.orderByHistoricTaskInstanceEndTime()
.desc()
.list()
return historicTasks.map { task ->
UserTaskHistory(
taskId = task.id,
taskName = task.name,
processName = task.processDefinitionName ?: "未知流程",
startTime = task.startTime,
endTime = task.endTime,
duration = task.durationInMillis,
assignee = task.assignee
)
}
}
}示例2:任务执行效率统计
kotlin
import org.flowable.engine.HistoryService
import org.springframework.stereotype.Service
import java.util.Date
data class TaskEfficiencyStats(
val taskDefinitionKey: String,
val taskName: String,
val totalCount: Long,
val avgDurationHours: Double,
val maxDurationHours: Double,
val minDurationHours: Double
)
@Service
class TaskEfficiencyAnalyzer(
private val historyService: HistoryService
) {
/**
* 统计任务执行效率
* 企业场景:流程优化,分析各环节的平均处理时长
*/
fun analyzeTaskEfficiency(
processDefinitionKey: String,
startDate: Date,
endDate: Date
): List<TaskEfficiencyStats> {
// 查询该流程在时间范围内的所有已完成任务
val historicTasks = historyService.createHistoricTaskInstanceQuery()
.processDefinitionKey(processDefinitionKey)
.taskCompletedAfter(startDate)
.taskCompletedBefore(endDate)
.finished()
.list()
// 按任务定义分组统计
val taskGroups = historicTasks.groupBy { it.taskDefinitionKey }
return taskGroups.map { (taskKey, tasks) ->
val durations = tasks.mapNotNull { it.durationInMillis }
.map { it.toDouble() / (1000 * 60 * 60) } // 转换为小时
TaskEfficiencyStats(
taskDefinitionKey = taskKey,
taskName = tasks.first().name,
totalCount = tasks.size.toLong(),
avgDurationHours = if (durations.isNotEmpty()) durations.average() else 0.0,
maxDurationHours = durations.maxOrNull() ?: 0.0,
minDurationHours = durations.minOrNull() ?: 0.0
)
}
}
}示例3:查询请假审批链路
kotlin
import org.flowable.engine.HistoryService
import org.springframework.stereotype.Service
data class ApprovalStep(
val stepName: String,
val assignee: String,
val startTime: String,
val endTime: String?,
val duration: String,
val comment: String?
)
@Service
class ApprovalChainService(
private val historyService: HistoryService
) {
/**
* 查询流程的审批链路
* 企业场景:请假申请详情页,展示审批过程
*/
fun getApprovalChain(processInstanceId: String): List<ApprovalStep> {
val historicTasks = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.orderByHistoricTaskInstanceStartTime()
.asc()
.list()
return historicTasks.map { task ->
val duration = task.durationInMillis?.let {
val hours = it / (1000 * 60 * 60)
val minutes = (it % (1000 * 60 * 60)) / (1000 * 60)
"${hours}小时${minutes}分钟"
} ?: "进行中"
ApprovalStep(
stepName = task.name,
assignee = task.assignee ?: "待分配",
startTime = task.startTime.toString(),
endTime = task.endTime?.toString(),
duration = duration,
comment = null // 可以通过CommentService获取
)
}
}
}示例4:超时任务监控
kotlin
import org.flowable.engine.HistoryService
import org.springframework.stereotype.Service
import java.util.Calendar
import java.util.Date
data class TimeoutTask(
val taskId: String,
val taskName: String,
val processInstanceId: String,
val assignee: String?,
val startTime: Date,
val expectedDuration: Long, // 预期处理时长(小时)
val actualDuration: Long, // 实际已用时长(小时)
val isOverdue: Boolean
)
@Service
class TaskTimeoutMonitor(
private val historyService: HistoryService
) {
/**
* 监控超时任务
* 企业场景:任务预警系统,发现超时未处理的任务
*/
fun monitorTimeoutTasks(
processDefinitionKey: String,
expectedHours: Long = 24
): List<TimeoutTask> {
val timeoutDate = Calendar.getInstance().apply {
add(Calendar.HOUR, -expectedHours.toInt())
}.time
// 查询未完成且超过预期时长的任务
val unfinishedTasks = historyService.createHistoricTaskInstanceQuery()
.processDefinitionKey(processDefinitionKey)
.unfinished()
.taskCreatedBefore(timeoutDate)
.list()
val now = System.currentTimeMillis()
return unfinishedTasks.map { task ->
val actualHours = (now - task.startTime.time) / (1000 * 60 * 60)
TimeoutTask(
taskId = task.id,
taskName = task.name,
processInstanceId = task.processInstanceId,
assignee = task.assignee,
startTime = task.startTime,
expectedDuration = expectedHours,
actualDuration = actualHours,
isOverdue = actualHours > expectedHours
)
}
}
}示例5:用户工作量统计
kotlin
import org.flowable.engine.HistoryService
import org.springframework.stereotype.Service
import java.util.Date
import java.util.Calendar
data class UserWorkload(
val userId: String,
val totalTasks: Long,
val completedTasks: Long,
val pendingTasks: Long,
val avgProcessingHours: Double,
val completionRate: Double
)
@Service
class UserWorkloadService(
private val historyService: HistoryService
) {
/**
* 统计用户工作量
* 企业场景:月度绩效考核,统计员工任务完成情况
*/
fun getUserWorkload(userId: String, month: Int, year: Int): UserWorkload {
val startDate = Calendar.getInstance().apply {
set(year, month - 1, 1, 0, 0, 0)
}.time
val endDate = Calendar.getInstance().apply {
set(year, month, 1, 0, 0, 0)
}.time
// 查询该用户在该月的所有任务
val allTasks = historyService.createHistoricTaskInstanceQuery()
.taskAssignee(userId)
.taskCreatedAfter(startDate)
.taskCreatedBefore(endDate)
.list()
val completedTasks = allTasks.filter { it.endTime != null }
val pendingTasks = allTasks.filter { it.endTime == null }
val avgHours = if (completedTasks.isNotEmpty()) {
val totalDuration = completedTasks.mapNotNull { it.durationInMillis }.sum()
(totalDuration.toDouble() / completedTasks.size) / (1000 * 60 * 60)
} else 0.0
val completionRate = if (allTasks.isNotEmpty()) {
(completedTasks.size.toDouble() / allTasks.size) * 100
} else 0.0
return UserWorkload(
userId = userId,
totalTasks = allTasks.size.toLong(),
completedTasks = completedTasks.size.toLong(),
pendingTasks = pendingTasks.size.toLong(),
avgProcessingHours = avgHours,
completionRate = completionRate
)
}
}示例6:任务历史REST API
kotlin
import org.flowable.engine.HistoryService
import org.springframework.format.annotation.DateTimeFormat
import org.springframework.web.bind.annotation.*
import java.util.Date
@RestController
@RequestMapping("/api/history/tasks")
class HistoricTaskController(
private val historyService: HistoryService
) {
/**
* 查询任务历史
*/
@GetMapping
fun listHistoricTasks(
@RequestParam(required = false) assignee: String?,
@RequestParam(required = false) processInstanceId: String?,
@RequestParam(required = false) taskName: String?,
@RequestParam(required = false) finished: Boolean?,
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") startDate: Date?,
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") endDate: Date?,
@RequestParam(defaultValue = "1") page: Int,
@RequestParam(defaultValue = "10") size: Int
): Map<String, Any> {
val query = historyService.createHistoricTaskInstanceQuery()
assignee?.let { query.taskAssignee(it) }
processInstanceId?.let { query.processInstanceId(it) }
taskName?.let { query.taskNameLike("%$it%") }
startDate?.let { query.taskCreatedAfter(it) }
endDate?.let { query.taskCreatedBefore(it) }
finished?.let {
if (it) query.finished() else query.unfinished()
}
val total = query.count()
val tasks = query
.orderByHistoricTaskInstanceEndTime()
.desc()
.listPage((page - 1) * size, size)
return mapOf(
"data" to tasks.map { task ->
mapOf(
"taskId" to task.id,
"taskName" to task.name,
"assignee" to task.assignee,
"startTime" to task.startTime,
"endTime" to task.endTime,
"duration" to task.durationInMillis,
"processInstanceId" to task.processInstanceId
)
},
"total" to total,
"page" to page,
"size" to size
)
}
}注意事项
1. 历史数据范围
- 查询包含所有任务:已完成、未完成、已删除
- 使用
finished()只查询已完成的任务 - 使用
unfinished()只查询未完成的任务
2. 性能优化
- 添加时间范围条件,避免全表扫描
- 大数据量必须使用分页查询
- 考虑对历史表建立索引
3. 任务时长计算
durationInMillis只有已完成的任务才有值- 未完成的任务需要手动计算:当前时间 - 开始时间
4. 多租户隔离
- 多租户场景必须添加
processInstanceTenantId()条件
5. 删除的任务
- 即使任务被删除,历史记录仍然存在
- 可通过
deleteReason判断任务删除原因
相关 API
HistoryService.createHistoricTaskInstanceQuery()- 创建查询HistoryService.createHistoricProcessInstanceQuery()- 查询流程历史HistoryService.createHistoricActivityInstanceQuery()- 查询活动历史HistoryService.createHistoricVariableInstanceQuery()- 查询变量历史HistoryService.deleteHistoricTaskInstance()- 删除任务历史
最佳实践
1. 定期归档历史任务
kotlin
@Scheduled(cron = "0 0 3 * * ?")
fun archiveHistoricTasks() {
val sixMonthsAgo = Calendar.getInstance().apply {
add(Calendar.MONTH, -6)
}.time
val oldTasks = historyService.createHistoricTaskInstanceQuery()
.finished()
.taskCompletedBefore(sixMonthsAgo)
.list()
// 归档逻辑...
}2. 缓存统计结果
kotlin
@Cacheable("taskStats")
fun getCachedTaskStats(userId: String, month: Int, year: Int) {
return getUserWorkload(userId, month, year)
}本文档说明
- 基于 Flowable 7.1.0 版本编写
- 所有示例均可直接在 Spring Boot + Kotlin 项目中使用
- 示例场景来自真实企业应用,具有实际参考价值