AbstractWorkflowService
/** | |
* 抽象工作流接口(有部分功能的实现) | |
* | |
* @author HenryYan | |
* | |
*/ | |
public abstract class AbstractWorkflowService<T extends BaseWorkflowEntity, PK extends Serializable> { | |
protected Logger logger = LoggerFactory.getLogger(getClass()); | |
@Autowired | |
protected RuntimeService runtimeService; | |
@Autowired | |
protected TaskService taskService; | |
@Autowired | |
protected RepositoryService repositoryService; | |
@Autowired | |
protected HistoryService historyService; | |
private Class<?> entityKeyClazz; | |
public AbstractWorkflowService() { | |
super(); | |
entityKeyClazz = ReflectionUtils.getSuperClassGenricType(getClass(), 1); | |
} | |
/** | |
* 启动流程 | |
* @param entity 实体 | |
* @return 启动后的流程实例 | |
* @throws IllegalAccessException 设置processInstanceId时 | |
* @throws InvocationTargetException 设置processInstanceId时 | |
* @throws NoSuchMethodException 设置processInstanceId时 | |
*/ | |
protected ProcessInstance start(T entity, User user) throws IllegalAccessException, InvocationTargetException, | |
NoSuchMethodException, Exception { | |
return start(entity, user, null); | |
} | |
/** | |
* 启动流程 | |
* @param entity 实体 | |
* @param user 用户 | |
* @param variables 启动流程的变量 | |
* @return 启动后的流程实例 | |
* @throws IllegalAccessException 设置processInstanceId时 | |
* @throws InvocationTargetException 设置processInstanceId时 | |
* @throws NoSuchMethodException 设置processInstanceId时 | |
*/ | |
protected ProcessInstance start(T entity, User user, Map<String, Object> variables) throws IllegalAccessException, | |
InvocationTargetException, NoSuchMethodException, Exception { | |
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(getProcessDefKey(), entity.getId().toString(), | |
variables); | |
PropertyUtils.setProperty(entity, "processInstanceId", processInstance.getId()); | |
getEntityManager().saveEntity(entity); | |
return processInstance; | |
} | |
/** | |
* 启动工作流 | |
* @param entity 实体 | |
* @param user 用户 | |
* @param variables 启动流程的变量 | |
* @return 响应结果,用map形式返回以便前台读取JSON格式数据 | |
* @throws Exception | |
*/ | |
public Map<String, Object> startWorkflow(T entity, User user, Map<String, Object> variables) throws Exception { | |
if (EntityUtils.isNew(entity.getId())) { | |
getEntityManager().saveEntity(entity); | |
} | |
ProcessInstance processInstance = start(entity, user, variables); | |
Map<String, Object> responses = new HashMap<String, Object>(); | |
responses.put("bkey", entity.getId()); | |
responses.put("pid", processInstance.getId()); | |
responses.put("success", true); | |
responses.put("started", true); | |
logger.debug("started workflow, entity={}, user={}, responses={}", | |
new Object[] { entity, user.getLoginName(), responses }); | |
return responses; | |
} | |
/** | |
* 启动工作流 | |
* @param entity 实体 | |
* @return 响应结果,用map形式返回以便前台读取JSON格式数据 | |
* @throws Exception | |
*/ | |
public Map<String, Object> startWorkflow(T entity, User user) throws Exception { | |
return startWorkflow(entity, user, null); | |
} | |
/** | |
* 完成任务 | |
* @param taskId | |
* @param user | |
* @param variables | |
*/ | |
public void complete(String taskId, User user, Map<String, Object> variables) throws Exception { | |
taskService.complete(taskId, variables); | |
logger.debug("complete task, id={}, user={}, variables={}", new Object[] { taskId, user.getLoginName(), variables }); | |
} | |
/** | |
* 根据任务名称查询任务集合 | |
* @param processDefKey 流程定义key | |
* @param taskDefKey 流程定义文件中的task英文名称 | |
* @return 实体集合,包含task属性 | |
* @throws Exception | |
*/ | |
@Transactional(readOnly = true) | |
public List<T> searchTasksWithEntities(String processDefKey, String taskDefKey) throws Exception { | |
if (StringUtils.isBlank(taskDefKey)) { | |
throw new IllegalArgumentException("taskDefKey can not be null"); | |
} | |
TaskQuery taskAssigneeQuery = taskService.createTaskQuery().processDefinitionKey(getProcessDefKey()) | |
.taskDefinitionKey(taskDefKey); | |
List<Task> tasks = taskAssigneeQuery.list(); | |
List<T> results = parseTaskToEntities(tasks); | |
return results; | |
} | |
/** | |
* 通过task对象转换为包含task属性的业务实体集合 | |
* @param tasks 工作流的task集合 | |
* @return 包含task属性的业务实体集合 | |
* @throws IllegalAccessException | |
* @throws InvocationTargetException | |
* @throws NoSuchMethodException | |
*/ | |
@SuppressWarnings("unchecked") | |
protected List<T> parseTaskToEntities(List<Task> tasks) throws IllegalAccessException, InvocationTargetException, | |
NoSuchMethodException { | |
// 缓存流程实例 | |
Set<String> processInstanceIdSet = new HashSet<String>(); | |
processInstanceIdSet.addAll(ConvertUtils.convertElementPropertyToList(tasks, "processInstanceId")); | |
List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery() | |
.processInstanceIds(processInstanceIdSet).list(); | |
Map<String, ProcessInstance> processInstanceMap = new HashMap<String, ProcessInstance>(); | |
for (ProcessInstance processInstance : processInstanceList) { | |
processInstanceMap.put(processInstance.getId(), processInstance); | |
} | |
// 缓存实体 | |
Map<String, T> entityMap = extractEntitiesFromDatabase(processInstanceList); | |
List<T> results = packageTasksUseEntity(tasks, entityMap, processInstanceMap); | |
return results; | |
} | |
/** | |
* 同一任务数量,包括:未签收、处理中、正在运行、已结束 | |
* @param userId 用户ID | |
* @return unsigned:未签收,todo:处理中,unfinished:运行中,finished:已完成 | |
*/ | |
@Transactional(readOnly = true) | |
public Map<String, Long> countTasks(String userId) { | |
Map<String, Long> workflowCounter = new HashMap<String, Long>(); | |
// 根据角色查询任务--未签收的 | |
TaskQuery taskCandidateUserQuery = createUnsignedTaskQuery(userId); | |
long taskForGroupCounter = taskCandidateUserQuery.count(); | |
workflowCounter.put("unsigned", taskForGroupCounter); | |
// 根据代理人查询任务--待处理 | |
TaskQuery taskAssigneeQuery = createTodoTaskQuery(userId); | |
long todoTaskCounter = taskAssigneeQuery.count(); | |
workflowCounter.put("todo", todoTaskCounter); | |
// 运行中流程 | |
// TODO 查询到底使用history还是runtime查询正在运行的流程 | |
ProcessInstanceQuery unfinishedQuery = createUnFinishedProcessInstanceQuery(userId); | |
long unFinishedCounter = unfinishedQuery.count(); | |
workflowCounter.put("unfinished", unFinishedCounter); | |
// TODO 已完结流程 | |
// 1、查询当前登录人的历史task | |
// 2、根据task的processInstanceId查询流程实例 | |
HistoricProcessInstanceQuery finishedQuery = createFinishedProcessInstanceQuery(userId); | |
long finishedCounter = finishedQuery.count(); | |
workflowCounter.put("finished", finishedCounter); | |
return workflowCounter; | |
} | |
/** | |
* 分页查询工作流数据并封装成业务实体 | |
* @param flowDataType 任务/实例状态,{@link WorkflowConstants} | |
* @param userId 用户ID | |
* @param page 分页对象 | |
* @return 包含工作流信息的业务实体 | |
* @throws Exception | |
*/ | |
@Transactional(readOnly = true) | |
public List<T> searchForPage(String flowDataType, String userId, Page<T> page) throws Exception { | |
List<T> results = null; | |
List<Task> tasks = null; | |
TaskQuery taskCandidateUserQuery = createUnsignedTaskQuery(userId); | |
TaskQuery taskAssigneeQuery = createTodoTaskQuery(userId); | |
// HistoricProcessInstanceQuery unfinishedQuery = getUnFinishedProcessInstanceQuery(userId); | |
ProcessInstanceQuery unfinishedQuery = createUnFinishedProcessInstanceQuery(userId); | |
HistoricProcessInstanceQuery finishedQuery = createFinishedProcessInstanceQuery(userId); | |
List<ProcessInstance> runtimeProcessInstances = null; | |
List<HistoricProcessInstance> historicProcessInstances = null; | |
if (flowDataType.equals(WorkflowConstants.TASK_STATUS_UNSIGNED)) { | |
if (!page.isOrderBySetted()) { | |
page.setOrderBy("task.priority,task.createTime"); | |
page.setOrder("desc,desc"); | |
} | |
setOrders(taskCandidateUserQuery, page); | |
tasks = taskCandidateUserQuery.listPage(page.getFirst() - 1, page.getPageSize()); | |
} else if (flowDataType.equals(WorkflowConstants.TASK_STATUS_TODO)) { | |
if (!page.isOrderBySetted()) { | |
page.setOrderBy("task.priority,task.createTime"); | |
page.setOrder("desc,desc"); | |
} | |
setOrders(taskAssigneeQuery, page); | |
tasks = taskAssigneeQuery.listPage(page.getFirst() - 1, page.getPageSize()); | |
} else if (flowDataType.equals(WorkflowConstants.PROCESS_INSTANCE_STATUS_UNFINISHED)) { | |
setOrders(unfinishedQuery, page); | |
runtimeProcessInstances = unfinishedQuery.listPage(page.getFirst() - 1, page.getPageSize()); | |
} else if (flowDataType.equals(WorkflowConstants.PROCESS_INSTANCE_STATUS_FINISHED)) { | |
if (!page.isOrderBySetted()) { | |
page.setOrderBy("historicProcessInstance.endTime"); | |
page.setOrder("desc"); | |
} | |
setOrders(finishedQuery, page); | |
historicProcessInstances = finishedQuery.listPage(page.getFirst() - 1, page.getPageSize()); | |
} | |
if (tasks != null && !tasks.isEmpty()) { | |
results = this.parseTaskToEntities(tasks); | |
} else if (historicProcessInstances != null && !historicProcessInstances.isEmpty()) { | |
results = packageHistoricProcessInstances(flowDataType, historicProcessInstances); | |
} else if (runtimeProcessInstances != null && !runtimeProcessInstances.isEmpty()) { | |
// TODO 对于嵌入式子流程,父流程显示当前节点为null | |
/*for (ProcessInstance processInstance : runtimeProcessInstances) { | |
ExecutionEntity executionEntity = (ExecutionEntity) processInstance; | |
if (processInstance.getBusinessKey() == null) { | |
} | |
}*/ | |
results = packageRuntimeProcessInstances(flowDataType, runtimeProcessInstances); | |
} | |
return results; | |
} | |
/** | |
* 设置查询对象的排序条件 | |
* @param query | |
* @param page | |
* @throws NoSuchMethodException | |
* @throws SecurityException | |
*/ | |
private void setOrders(Query<?, ?> query, Page<T> page) throws SecurityException, NoSuchMethodException { | |
if (!page.isOrderBySetted()) { | |
return; | |
} | |
String[] orderArray = StringUtils.split(page.getOrder(), ','); | |
String[] orderByArray = StringUtils.split(page.getOrderBy(), ','); | |
for (int i = 0; i < orderByArray.length; i++) { | |
String orderBy = orderByArray[i]; | |
String order = orderArray[i]; | |
System.out.println(orderBy + "=" + order); | |
if (orderBy.startsWith("task.")) { | |
String innerOrderBy = orderBy.split("\\.")[1]; | |
String withFirstUpperCharOrderBy = StringUtils.upperCase(innerOrderBy.substring(0, 1)) | |
+ innerOrderBy.substring(1); | |
String methodName = "orderByTask" + withFirstUpperCharOrderBy; | |
ReflectionUtils.invokeMethod(query, methodName, null, null); | |
ReflectionUtils.invokeMethod(query, order, null, null); | |
} else if (orderBy.startsWith("historicProcessInstance.")) { | |
String innerOrderBy = orderBy.split("\\.")[1]; | |
String withFirstUpperCharOrderBy = StringUtils.upperCase(innerOrderBy.substring(0, 1)) | |
+ innerOrderBy.substring(1); | |
String methodName = "orderByProcessInstance" + withFirstUpperCharOrderBy; | |
ReflectionUtils.invokeMethod(query, methodName, null, null); | |
ReflectionUtils.invokeMethod(query, order, null, null); | |
} | |
} | |
} | |
/** | |
* 获取已经完成的流程实例查询对象 | |
* @param userId 用户ID | |
*/ | |
@Transactional(readOnly = true) | |
public HistoricProcessInstanceQuery createFinishedProcessInstanceQuery(String userId) { | |
HistoricProcessInstanceQuery finishedQuery = historyService.createHistoricProcessInstanceQuery() | |
.processDefinitionKey(getProcessDefKey()).finished(); | |
return finishedQuery; | |
} | |
// /** | |
// * 获取未经完成的流程实例查询对象 | |
// * @param userId 用户ID | |
// */ | |
// @Transactional(readOnly = true) | |
// public HistoricProcessInstanceQuery getUnFinishedProcessInstanceQuery(String userId) { | |
// HistoricProcessInstanceQuery unfinishedQuery = historyService.createHistoricProcessInstanceQuery().processDefinitionKey(getProcessName()) | |
// .unfinished(); | |
// return unfinishedQuery; | |
// } | |
/** | |
* 获取未经完成的流程实例查询对象 | |
* @param userId 用户ID | |
*/ | |
@Transactional(readOnly = true) | |
public ProcessInstanceQuery createUnFinishedProcessInstanceQuery(String userId) { | |
ProcessInstanceQuery unfinishedQuery = runtimeService.createProcessInstanceQuery().processDefinitionKey(getProcessDefKey()) | |
.active(); | |
return unfinishedQuery; | |
} | |
/** | |
* 获取正在处理的任务查询对象 | |
* @param userId 用户ID | |
*/ | |
@Transactional(readOnly = true) | |
public TaskQuery createTodoTaskQuery(String userId) { | |
TaskQuery taskAssigneeQuery = taskService.createTaskQuery().processDefinitionKey(getProcessDefKey()).taskAssignee(userId); | |
return taskAssigneeQuery; | |
} | |
/** | |
* 获取未签收的任务查询对象 | |
* @param userId 用户ID | |
*/ | |
@Transactional(readOnly = true) | |
public TaskQuery createUnsignedTaskQuery(String userId) { | |
TaskQuery taskCandidateUserQuery = taskService.createTaskQuery().processDefinitionKey(getProcessDefKey()) | |
.taskCandidateUser(userId); | |
return taskCandidateUserQuery; | |
} | |
/** | |
* 从流程实例中抽取businessKey属性,然后根据这些属性从数据库查询业务对象 | |
* @param processInstanceList 流程实例集合 | |
* @return Map<实体ID, 实体对象> | |
*/ | |
@SuppressWarnings("unchecked") | |
@Transactional(readOnly = true) | |
protected Map<String, T> extractEntitiesFromDatabase(List<?> processInstanceList) { | |
List<String> businessKeys = ConvertUtils.convertElementPropertyToList(processInstanceList, "businessKey"); | |
List<PK> entityIds = new ArrayList<PK>(); | |
for (String string : businessKeys) { | |
entityIds.add((PK) ConvertUtils.convertStringToObject(string, entityKeyClazz)); | |
} | |
Map<String, T> entityMap = new HashMap<String, T>(); | |
List<T> entities = getEntityManager().getEntities(entityIds.toArray()); | |
for (T entity : entities) { | |
entityMap.put(entity.getId().toString(), entity); | |
} | |
return entityMap; | |
} | |
/** | |
* 绑定业务实体和任务的关系 | |
* @param tasks 任务集合 | |
* @param entityMap 实体集合,作用:内存缓存 | |
* @param processInstanceMap 流程实例集合 | |
* @return 设置了task、processDefinition、processInstance属性 | |
* @throws IllegalAccessException 克隆流程对象时 | |
* @throws InvocationTargetException 克隆流程对象时 | |
* @throws NoSuchMethodException 克隆流程对象时 | |
* @see {@link WorkflowUtils} | |
*/ | |
@Transactional(readOnly = true) | |
protected List<T> packageTasksUseEntity(List<Task> tasks, Map<String, T> entityMap, | |
Map<String, ProcessInstance> processInstanceMap) throws IllegalAccessException, InvocationTargetException, | |
NoSuchMethodException { | |
List<T> results = new ArrayList<T>(); | |
Map<String, ProcessDefinition> processDefinitionMap = new HashMap<String, ProcessDefinition>(); | |
for (Task task : tasks) { | |
ProcessInstance processInstance = processInstanceMap.get(task.getProcessInstanceId()); | |
String processDefinitionId = processInstance.getProcessDefinitionId(); | |
ProcessDefinition processDefinition = processDefinitionMap.get(processDefinitionId); | |
if (processDefinition == null) { | |
processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId) | |
.singleResult(); | |
} | |
if (processInstance != null) { | |
String businessKey = processInstance.getBusinessKey(); | |
T workflowEntity = entityMap.get(businessKey); | |
if (workflowEntity == null) { | |
continue; | |
} | |
workflowEntity.setProcessInstance(WorkflowUtils.cloneExProcessInstance(processInstance)); | |
ExTask cloneExTask = WorkflowUtils.cloneExTask(task); | |
cloneExTask.setVariables(runtimeService.getVariables(task.getExecutionId())); | |
workflowEntity.setTask(cloneExTask); | |
workflowEntity.setProcessDefinition(WorkflowUtils.cloneExProcessDefinition(processDefinition)); | |
results.add(workflowEntity); | |
} | |
} | |
return results; | |
} | |
/** | |
* 绑定业务实体和<b>已结束</b>流程实例的关系 | |
* @param flowDataType 流程状态,{@link WorkflowConstants} | |
* @param processInstances 历史流程实例集合 | |
* @return 实体集合,设置了historicProcessInstance属性 | |
* @throws IllegalAccessException 克隆流程对象时 | |
* @throws InvocationTargetException 克隆流程对象时 | |
* @throws NoSuchMethodException 克隆流程对象时 | |
* @see {@link WorkflowUtils} | |
*/ | |
@Transactional(readOnly = true) | |
protected List<T> packageHistoricProcessInstances(String flowDataType, List<HistoricProcessInstance> processInstances) | |
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { | |
List<T> results = new ArrayList<T>(); | |
Map<String, T> entityMap = extractEntitiesFromDatabase(processInstances); | |
for (HistoricProcessInstance historicProcessInstance : processInstances) { | |
String businessKey = historicProcessInstance.getBusinessKey(); | |
ExHistoricProcessInstance exHistoricProcessInstance = WorkflowUtils | |
.cloneExHistoricProcessInstance(historicProcessInstance); | |
T workflowEntity = entityMap.get(businessKey); | |
if (workflowEntity == null) { | |
continue; | |
} | |
workflowEntity.setHistoricProcessInstance(exHistoricProcessInstance); | |
results.add(workflowEntity); | |
} | |
return results; | |
} | |
/** | |
* 绑定业务实体和<b>正在运行</b>的流程实例的关系 | |
* @param flowDataType 流程状态,{@link WorkflowConstants} | |
* @param runtimeProcessInstances 运行中的流程实例集合 | |
* @return 实体集合,设置了processInstance属性 | |
* @throws IllegalAccessException 克隆流程对象时 | |
* @throws InvocationTargetException 克隆流程对象时 | |
* @throws NoSuchMethodException 克隆流程对象时 | |
* @see {@link WorkflowUtils} | |
*/ | |
@Transactional(readOnly = true) | |
protected List<T> packageRuntimeProcessInstances(String flowDataType, List<ProcessInstance> runtimeProcessInstances) | |
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { | |
List<T> results = new ArrayList<T>(); | |
Map<String, T> entityMap = extractEntitiesFromDatabase(runtimeProcessInstances); | |
for (ProcessInstance runtimeProcessInstance : runtimeProcessInstances) { | |
String businessKey = runtimeProcessInstance.getBusinessKey(); | |
ExProcessInstance exProcessInstance = WorkflowUtils.cloneExProcessInstance(runtimeProcessInstance); | |
T workflowEntity = entityMap.get(businessKey); | |
if (workflowEntity == null) { | |
continue; | |
} | |
workflowEntity.setProcessInstance(exProcessInstance); | |
if (flowDataType.equals(WorkflowConstants.PROCESS_INSTANCE_STATUS_UNFINISHED)) { | |
Task singleResult = taskService.createTaskQuery().processInstanceId(runtimeProcessInstance.getId()) | |
.orderByTaskCreateTime().desc().singleResult(); | |
workflowEntity.setTask(WorkflowUtils.cloneExTask(singleResult)); | |
} | |
results.add(workflowEntity); | |
} | |
return results; | |
} | |
/** | |
* 获取流程定义key | |
* @return 流程定义key | |
*/ | |
@Transactional(readOnly = true) | |
public abstract String getProcessDefKey(); | |
/** | |
* 获取实体管理类 | |
* | |
* @return ${@link BaseEntityManager} | |
*/ | |
public abstract BaseEntityManager<T, PK> getEntityManager(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment