news 2026/4/14 13:52:56

查询指定任务的办理时间轴

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
查询指定任务的办理时间轴

一、接口核心需求分析

你提供的这段代码是Activiti工作流中查询指定任务的办理时间轴接口,核心业务需求如下:

  1. 关联查询:根据传入的任务ID(taskId),先获取对应的流程实例ID(processInstanceId);
  2. 历史轨迹查询:查询该流程实例下所有“用户任务(userTask)”的历史执行记录,按任务开始时间升序排列;
  3. 数据格式化:将历史任务记录转换为前端易展示的TaskInfo对象,包含任务名称、办理人、开始/结束时间、审批意见等核心信息;
  4. 结果返回:返回结构化的任务办理时间轴列表,支撑前端展示流程审批轨迹。

二、代码逐段解析(核心逻辑+设计思路)

1. 流程实例ID关联
StringprocessInstanceId=taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
  • 设计思路
    • 通过TaskServicetaskQuerytaskId查询具体任务,获取该任务所属的流程实例ID;
    • 这是“任务→流程实例→历史任务”关联的核心步骤,因为历史任务需按流程实例维度查询。
  • 风险点singleResult()可能返回null(如taskId不存在),直接调用getProcessInstanceId()会抛出空指针异常。
2. 历史用户任务查询
List<HistoricActivityInstance>history=historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)// 按流程实例过滤.activityType("userTask")// 仅查询用户任务(排除网关、开始/结束节点等).orderByHistoricActivityInstanceStartTime().asc()// 按开始时间升序(时间轴顺序).list();
  • 设计思路
    • 借助HistoryServiceHistoricActivityInstanceQuery查询流程实例的历史活动记录;
    • 核心过滤条件activityType("userTask"):只保留人工办理的任务,过滤自动节点(如网关、服务任务),符合“办理时间轴”的业务场景;
    • 排序规则:按任务开始时间升序,保证时间轴从流程发起→后续审批的顺序展示。
3. 历史数据转换为前端DTO
List<TaskInfo>infos=newArrayList<>();SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");history.stream().forEach(h->{TaskInfoinfo=newTaskInfo();info.setProcessInstanceId(h.getProcessInstanceId());info.setStartTime(sdf.format(h.getStartTime()));if(h.getEndTime()!=null){info.setEndTime(sdf.format(h.getEndTime()));}info.setAssignee(h.getAssignee());// 任务办理人info.setTaskName(h.getActivityName());// 任务名称(如“采购经理审批”)// 查询任务审批意见List<Comment>comments=taskService.getTaskComments(h.getTaskId());if(comments.size()>0){info.setComment(comments.get(0).getFullMessage());}infos.add(info);});
  • 设计思路
    • 数据适配:将Activiti原生的HistoricActivityInstance对象转换为自定义TaskInfo(前端DTO),屏蔽框架底层字段,只返回业务所需信息;
    • 时间格式化:将Date类型的开始/结束时间转换为“yyyy-MM-dd HH:mm:ss”字符串,便于前端展示;
    • 审批意见关联:通过taskService.getTaskComments(h.getTaskId())查询任务的审批备注(评论),取第一条作为核心意见。

三、核心问题与优化方案

1. 空指针异常(最高优先级优化)

原代码存在多处空指针风险,需补充校验:

@ApiOperation("任务办理时间轴")@RequestMapping(value="/history/{taskId}",method=RequestMethod.GET)@ResponseBodypublicList<TaskInfo>history(@PathVariableStringtaskId){// 1. 校验入参if(StringUtils.isBlank(taskId)){returnCollections.emptyList();// 或返回AjaxResult提示参数为空}// 2. 查询任务时校验nullTasktask=taskService.createTaskQuery().taskId(taskId).singleResult();if(task==null){returnCollections.emptyList();// 无对应任务,返回空列表}StringprocessInstanceId=task.getProcessInstanceId();// 3. 查询历史任务List<HistoricActivityInstance>history=historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().list();List<TaskInfo>infos=newArrayList<>();SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 4. 遍历历史任务时避免空指针for(HistoricActivityInstanceh:history){if(h==null){continue;}TaskInfoinfo=newTaskInfo();info.setProcessInstanceId(h.getProcessInstanceId());// 时间格式化校验if(h.getStartTime()!=null){info.setStartTime(sdf.format(h.getStartTime()));}if(h.getEndTime()!=null){info.setEndTime(sdf.format(h.getEndTime()));}info.setAssignee(h.getAssignee());info.setTaskName(h.getActivityName());// 审批意见查询(校验taskId非空)if(StringUtils.isNotBlank(h.getTaskId())){List<Comment>comments=taskService.getTaskComments(h.getTaskId());if(comments!=null&&!comments.isEmpty()){info.setComment(comments.get(0).getFullMessage());}}infos.add(info);}returninfos;}
2. 性能优化
  • 问题:遍历历史任务时,每次调用taskService.getTaskComments(h.getTaskId())都会发起一次数据库查询,若历史任务较多(如10+),会产生N+1查询问题;
  • 优化方案:批量查询所有任务的审批意见,减少数据库交互:
    // 1. 先收集所有历史任务IDList<String>taskIds=history.stream().filter(h->StringUtils.isNotBlank(h.getTaskId())).map(HistoricActivityInstance::getTaskId).collect(Collectors.toList());// 2. 批量查询评论(需自定义SQL/扩展API,Activiti原生无批量查询评论接口)// 示例:通过自定义Mapper批量查询Map<String,Comment>taskCommentMap=commentMapper.getCommentByTaskIds(taskIds);// 3. 遍历历史任务时直接从Map取值for(HistoricActivityInstanceh:history){// ... 其他赋值逻辑Commentcomment=taskCommentMap.get(h.getTaskId());if(comment!=null){info.setComment(comment.getFullMessage());}}
3. 时间格式化优化
  • 问题SimpleDateFormat是非线程安全的,若接口高并发调用,可能出现时间格式化错误;
  • 优化方案:使用DateTimeFormatter(Java 8+)替代:
    DateTimeFormatterformatter=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");// 时间格式化if(h.getStartTime()!=null){info.setStartTime(h.getStartTime().toInstant().atZone(ZoneId.systemDefault()).format(formatter));}if(h.getEndTime()!=null){info.setEndTime(h.getEndTime().toInstant().atZone(ZoneId.systemDefault()).format(formatter));}
4. 异常处理

补充全局异常捕获,避免接口抛出未处理的异常:

@ApiOperation("任务办理时间轴")@RequestMapping(value="/history/{taskId}",method=RequestMethod.GET)@ResponseBodypublicAjaxResulthistory(@PathVariableStringtaskId){// 改为返回统一响应体try{// 核心逻辑(上述优化后的代码)List<TaskInfo>infos=...;returnAjaxResult.success(infos);}catch(Exceptione){log.error("查询任务办理时间轴失败,taskId:{}",taskId,e);returnAjaxResult.error("查询任务办理轨迹失败:"+e.getMessage());}}

四、设计维度温习

1. 架构设计
  • 分层设计:接口属于“应用层”,依赖Activiti的TaskService/HistoryService(领域层)完成数据查询,符合分层架构规范;
  • DTO设计:通过TaskInfo封装前端所需字段,实现“领域模型→展示模型”的解耦,避免直接返回框架原生对象。
2. 扩展性设计
  • 多维度过滤:可扩展支持按“办理人、任务状态、时间范围”过滤历史任务,例如:
    // 扩展:仅查询指定办理人的任务historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").assignee("zhangsan")// 扩展过滤条件.list();
  • 多语言适配:时间格式化可扩展支持国际化(如DateTimeFormatter结合Locale);
  • 审批意见扩展:原代码仅取第一条评论,可扩展返回所有评论,或按评论类型过滤(如“审批意见/备注”)。
3. 安全与规范
  • 权限控制:建议添加权限校验(如@PreAuthorize),仅允许流程参与人/管理员查询时间轴;
  • 日志规范:添加入参、出参日志,便于问题排查:
    log.info("查询任务办理时间轴,taskId:{}",taskId);log.info("查询结果:{}",infos.size());

五、核心总结

维度核心要点
需求核心按任务ID关联流程实例,查询所有用户任务的历史轨迹,格式化后返回办理时间、办理人、审批意见等信息
设计亮点聚焦“用户任务”过滤非业务节点,按时间升序保证时间轴顺序,适配前端展示格式
优化方向1. 补充空指针校验;2. 替换线程不安全的SimpleDateFormat;3. 批量查询评论避免N+1;4. 统一异常处理和日志;5. 添加权限控制
扩展场景支持多条件过滤、多语言时间格式化、批量返回审批意见

该接口是工作流审批轨迹展示的核心接口,优化后可解决空指针、性能、线程安全等问题,同时保持良好的扩展性,适配企业级应用的生产环境需求。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 9:56:29

ubuntu系统_每天定时23:00 定时关机_怎么实现

在Ubuntu系统中设置每天23:00定时关机&#xff0c;最可靠的方法是使用系统内置的 cron 服务。下面的表格汇总了实现步骤和关键要点&#xff0c;你可以快速了解整个过程。步骤核心操作说明/命令示例1. 编辑计划任务终端中输入 sudo crontab -e使用 sudo 获取root权限&#xff0c…

作者头像 李华
网站建设 2026/4/14 10:11:13

mysql一条sql语句是如何运行的

MySQL SQL 语句执行流程MySQL 执行一条 SQL 语句的过程可以分为多个阶段&#xff0c;包括连接管理、解析与优化、执行引擎处理以及结果返回。以下是详细流程&#xff1a;连接管理客户端通过 TCP/IP 或 Unix Socket 连接到 MySQL 服务器。连接建立后&#xff0c;服务器进行身份验…

作者头像 李华
网站建设 2026/4/14 13:56:18

基于深度学习的空气质量预测研究(源码+万字报告+讲解)(支持资料、图片参考_相关定制)

摘要 由于环境恶化对人类健康、经济和日常生活的不利影响&#xff0c;空气质量问题逐渐引起了全世界的关注。大量研究表明&#xff0c;空气污染会对人类健康造成巨大危害&#xff0c;因此应采取措施预防和控制空气污染现象&#xff0c;减少空气污染对人类和地球造成的损害。随着…

作者头像 李华
网站建设 2026/4/12 4:43:34

Thinkphp和Laravel框架的海关出入口货物报关统筹管理系统_szdhjj06

目录摘要概述技术架构对比核心功能模块性能与安全优化实施效果与扩展性项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理摘要概述 ThinkPHP和Laravel框架在海关出入口货物报关统筹管理系统中的应用&#xff0c;展现了现代PHP框架在复杂业务场景下的…

作者头像 李华
网站建设 2026/4/12 22:56:43

【接口测试】1_Dubbo接口 _xx健康项目

文章目录 一、xx健康项目介绍1.1 项目描述1.2 目标用户群体1.3 项目模块1.4 系统框架 二、接口测试范围 一、xx健康项目介绍 1.1 项目描述 xx健康管理系统&#xff0c;是一款应用于健康管理机构的业务系统。采用可视化界面管理&#xff0c;提高健康管理师工作效率&#xff0c…

作者头像 李华
网站建设 2026/4/12 14:30:58

MySQL 创建新用户及授予权限的完整流程

1. 连接到MySQL数据库 首先&#xff0c;以管理员身份连接到MySQL数据库&#xff0c;通常是root用户&#xff1a; mysql -u root -p系统会提示输入管理员用户的密码&#xff0c;输入密码后进入MySQL的命令行。 2. 创建新用户 使用CREATE USER命令来创建一个新的MySQL用户。这个命…

作者头像 李华