查询用户审批信息本质是查询的act_hi_comment表。act_hi_comment表存储的是“批注”。
这张表中最重要的两个属性是:“批注人”、“批注”。当然,还存储了任务ID与流程实例ID。
TASK_ID_ 是任务ID。
PROC_INST_ID 是流程实例ID。
通过日志打印出来的SQL语句如下:
select * from ACT_HI_COMMENT where PROC_INST_ID_ = ? order by TIME_ desc
SQL语句中的"?"代表的是 流程实例的ID:5016。
我们知道,一个流程实例包含着一些列任务。所以,为了查询出这些任务和多个上级对不同任务的“批注”,查询条件设置为“流程实例ID”还是很合理的。
很值得一提的是,这张act_hi_comment表虽然已act_hi开头,但是却不是通过 HistoryService进行查询,而是通过TaskService进行查询。另外,为这张表插入数据的时候,用的Service也是TaskService。
查询这张表的核心代码如下:
List<Comment> comments = taskService.getProcessInstanceComments(executionId);//executinoId是流程实例ID
代码虽然简单,但是对于前后端对接起来却不容易。
Comment是工作流框架提供的一个接口,并不是一个实体对象。
而前端框架需要上述查询出来的comments集合中数据,并且要求为JSON格式。
直接使用@ResponseBody返回会报错,我试了很多次。
原因很简单,comments的泛型是是接口,不是实体。
Comment接口定义如下:
package org.activiti.engine.task;
import java.util.Date;
import org.activiti.engine.history.HistoricData;
public interface Comment extends HistoricData {
String getId();
String getUserId();
Date getTime();
String getTaskId();
String getProcessInstanceId();
String getType();
String getFullMessage();
}
Activity工作流提供了Comment接口的实现,就是一些get/set方法,我就省略了。
package org.activiti.engine.impl.persistence.entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import org.activiti.engine.impl.db.PersistentObject;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Event;
public class CommentEntity implements Comment, Event, PersistentObject, Serializable {
private static final long serialVersionUID = 1L;
public static final String TYPE_EVENT = "event";
public static final String TYPE_COMMENT = "comment";
protected String id;
protected String type;
protected String userId;
protected Date time;
protected String taskId;
protected String processInstanceId;
protected String action;
protected String message;
protected String fullMessage;
public static String MESSAGE_PARTS_MARKER = "_|_";
public static Pattern MESSAGE_PARTS_MARKER_REGEX = Pattern.compile("_\\|_");
.....
}
为了能够复制CommentEntity的属性,我创建了一个与之相似的类,用于封装数据,准备返回给前端。
package com.ssi.domains.workflow.entity;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
/**
* Created by jay.zhou on 2018/7/2.
*/
@Getter
@Setter
public class MyCommentEntity {
private String id;
private String userId;//用户名,对应的是act_hi_comment表的USER_ID_字段
private Date date;
private String taskId;//任务id
private String processInstanceId;//流程定义id
private String message;//审批信息
private String fullMessage;
}
起初,为了实现属性的复制,我的代码是这样的。看起来又丑又长,那一串长长的set与get方法,着实令我不爽。我寻思着,能不能使用反射进行简化。在别的博主那里,我看到了一种思路。先获取俩个对象的字节码,再获取两个对象的所有Field,对比出相同的Field,然后进行属性复制。这种方法我觉得可行。但是想了一下,通过反射 Class中的getDeclaredFields() 方法获取到的两个数组,还要进行属性逐一比较,然后再进行逐一复制,还是挺麻烦的。
//从数据库中查询到的审批信息的集合,但是Comment是一个接口,需要我们自己创建一个实现类与之对应
List<Comment> comments = taskService.getProcessInstanceComments("5016");
//创建我们自己的list集合
List<MyCommentEntity> list = Lists.newArrayList();
//为每一个查询到接口实现类复制属性到我们自己的类中,解析为前端JSON数据
for(Comment comment :comments){
//向下转型
CommentEntity commentEntity = (CommentEntity)comment;
//创建我们自己的类
MyCommentEntity myCommentEntity = new MyCommentEntity();
commentEntity.setId(myCommentEntity.getId());
commentEntity.setUserId(myCommentEntity.getUserId());
commentEntity.setMessage(myCommentEntity.getMessage());
commentEntity.setTaskId(myCommentEntity.getTaskId());
commentEntity.setProcessInstanceId(myCommentEntity.getProcessInstanceId());
//添加我们自己的类
list.add(myCommentEntity);
}
return list;
后来,搜集了其它资料后,发现Spring带的BeanUtils类封装了常用的反射操作。其中就有这个属性复制。因此,代码修改为:
TaskService taskService = (TaskService) bf.getBean("taskService");
//从数据库中查询到的审批信息的集合,但是Comment是一个接口,需要我们自己创建一个实现类与之对应
List<Comment> comments = taskService.getProcessInstanceComments("5016");
//创建我们自己的list集合
List<MyCommentEntity> list = Lists.newArrayList();
//为每一个查询到接口实现类复制属性到我们自己的类中,解析为前端JSON数据
for(Comment comment :comments){
//向下转型
CommentEntity commentEntity = (CommentEntity)comment;
//创建我们自己的类
MyCommentEntity myCommentEntity = new MyCommentEntity();
//属性复制,源属性为commentEntity, 目标属性为myCommentEntity
BeanUtils.copyProperties(commentEntity, myCommentEntity);
//添加我们自己的类
list.add(myCommentEntity);
}
BeanUtils.copyProperties(Source,Target);找到Source与Target相同的属性,把Source的属性值复制到Target中。
看到这么清爽的代码,心情好多了。反射,你成功引起了我的兴趣。
最新研究结果显示,Comment接口可以不用向下转型,一样能够进行属性复制。
上述代码可以改为 BeanUtils.copyProperties(comment,myCommentEntity);