http://blog.csdn.net/rosten/article/details/38300267java
1 package com.famousPro.process.service.impl; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.List; 6 import java.util.Map; 7 8 import org.activiti.engine.FormService; 9 import org.activiti.engine.HistoryService; 10 import org.activiti.engine.RepositoryService; 11 import org.activiti.engine.RuntimeService; 12 import org.activiti.engine.TaskService; 13 import org.activiti.engine.history.HistoricActivityInstance; 14 import org.activiti.engine.impl.RepositoryServiceImpl; 15 import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; 16 import org.activiti.engine.impl.persistence.entity.TaskEntity; 17 import org.activiti.engine.impl.pvm.PvmTransition; 18 import org.activiti.engine.impl.pvm.process.ActivityImpl; 19 import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl; 20 import org.activiti.engine.impl.pvm.process.TransitionImpl; 21 import org.activiti.engine.runtime.ProcessInstance; 22 import org.activiti.engine.task.Task; 23 24 import com.famousPro.common.service.impl.BaseServiceImp; 25 import com.famousPro.common.util.IDGenerator; 26 import com.famousPro.common.util.StringUtil; 27 import com.famousPro.process.service.ProcessCoreService; 28 import com.famousPro.process.service.ProcessOtherService; 29 30 /** 31 * 流程操做核心類<br> 32 * 此核心類主要處理:流程經過、駁回、會籤、轉辦、停止、掛起等核心操做<br> 33 * 34 * @author wangfuwei 35 * 36 */ 37 public class ProcessCoreServiceImpl extends BaseServiceImp implements 38 ProcessCoreService { 39 protected RepositoryService repositoryService; 40 41 protected RuntimeService runtimeService; 42 43 protected TaskService taskService; 44 45 protected FormService formService; 46 47 protected HistoryService historyService; 48 49 protected ProcessOtherService processOtherService; 50 51 /** 52 * 根據當前任務ID,查詢能夠駁回的任務節點 53 * 54 * @param taskId 55 * 當前任務ID 56 */ 57 public List<ActivityImpl> findBackAvtivity(String taskId) throws Exception { 58 List<ActivityImpl> rtnList = null; 59 if (processOtherService.isJointTask(taskId)) {// 會籤任務節點,不容許駁回 60 rtnList = new ArrayList<ActivityImpl>(); 61 } else { 62 rtnList = iteratorBackActivity(taskId, findActivitiImpl(taskId, 63 null), new ArrayList<ActivityImpl>(), 64 new ArrayList<ActivityImpl>()); 65 } 66 return reverList(rtnList); 67 } 68 69 /** 70 * 審批經過(駁回直接跳回功能需後續擴展) 71 * 72 * @param taskId 73 * 當前任務ID 74 * @param variables 75 * 流程存儲參數 76 * @throws Exception 77 */ 78 public void passProcess(String taskId, Map<String, Object> variables) 79 throws Exception { 80 List<Task> tasks = taskService.createTaskQuery().parentTaskId(taskId) 81 .taskDescription("jointProcess").list(); 82 for (Task task : tasks) {// 級聯結束本節點發起的會籤任務 83 commitProcess(task.getId(), null, null); 84 } 85 commitProcess(taskId, variables, null); 86 } 87 88 /** 89 * 駁回流程 90 * 91 * @param taskId 92 * 當前任務ID 93 * @param activityId 94 * 駁回節點ID 95 * @param variables 96 * 流程存儲參數 97 * @throws Exception 98 */ 99 public void backProcess(String taskId, String activityId, 100 Map<String, Object> variables) throws Exception { 101 if (StringUtil.isNull(activityId)) { 102 throw new Exception("駁回目標節點ID爲空!"); 103 } 104 105 // 查詢本節點發起的會籤任務,並結束 106 List<Task> tasks = taskService.createTaskQuery().parentTaskId(taskId) 107 .taskDescription("jointProcess").list(); 108 for (Task task : tasks) { 109 commitProcess(task.getId(), null, null); 110 } 111 112 // 查找全部並行任務節點,同時駁回 113 List<Task> taskList = findTaskListByKey(findProcessInstanceByTaskId( 114 taskId).getId(), findTaskById(taskId).getTaskDefinitionKey()); 115 for (Task task : taskList) { 116 commitProcess(task.getId(), variables, activityId); 117 } 118 } 119 120 /** 121 * 取回流程 122 * 123 * @param taskId 124 * 當前任務ID 125 * @param activityId 126 * 取回節點ID 127 * @throws Exception 128 */ 129 public void callBackProcess(String taskId, String activityId) 130 throws Exception { 131 if (StringUtil.isNull(activityId)) { 132 throw new Exception("目標節點ID爲空!"); 133 } 134 135 // 查找全部並行任務節點,同時取回 136 List<Task> taskList = findTaskListByKey(findProcessInstanceByTaskId( 137 taskId).getId(), findTaskById(taskId).getTaskDefinitionKey()); 138 for (Task task : taskList) { 139 commitProcess(task.getId(), null, activityId); 140 } 141 } 142 143 /** 144 * 停止流程(特權人直接審批經過等) 145 * 146 * @param taskId 147 */ 148 public void endProcess(String taskId) throws Exception { 149 ActivityImpl endActivity = findActivitiImpl(taskId, "end"); 150 commitProcess(taskId, null, endActivity.getId()); 151 } 152 153 /** 154 * 會籤操做 155 * 156 * @param taskId 157 * 當前任務ID 158 * @param userCodes 159 * 會籤人帳號集合 160 * @throws Exception 161 */ 162 public void jointProcess(String taskId, List<String> userCodes) 163 throws Exception { 164 for (String userCode : userCodes) { 165 TaskEntity task = (TaskEntity) taskService.newTask(IDGenerator 166 .generateID()); 167 task.setAssignee(userCode); 168 task.setName(findTaskById(taskId).getName() + "-會籤"); 169 task.setProcessDefinitionId(findProcessDefinitionEntityByTaskId( 170 taskId).getId()); 171 task.setProcessInstanceId(findProcessInstanceByTaskId(taskId) 172 .getId()); 173 task.setParentTaskId(taskId); 174 task.setDescription("jointProcess"); 175 taskService.saveTask(task); 176 } 177 } 178 179 /** 180 * 轉辦流程 181 * 182 * @param taskId 183 * 當前任務節點ID 184 * @param userCode 185 * 被轉辦人Code 186 */ 187 public void transferAssignee(String taskId, String userCode) { 188 taskService.setAssignee(taskId, userCode); 189 } 190 191 /** 192 * ***************************************************************************************************************************************************<br> 193 * ************************************************如下爲流程會籤操做核心邏輯******************************************************************************<br> 194 * ***************************************************************************************************************************************************<br> 195 */ 196 197 /** 198 * ***************************************************************************************************************************************************<br> 199 * ************************************************以上爲流程會籤操做核心邏輯******************************************************************************<br> 200 * ***************************************************************************************************************************************************<br> 201 */ 202 203 /** 204 * ***************************************************************************************************************************************************<br> 205 * ************************************************如下爲流程轉向操做核心邏輯******************************************************************************<br> 206 * ***************************************************************************************************************************************************<br> 207 */ 208 209 /** 210 * @param taskId 211 * 當前任務ID 212 * @param variables 213 * 流程變量 214 * @param activityId 215 * 流程轉向執行任務節點ID<br> 216 * 此參數爲空,默認爲提交操做 217 * @throws Exception 218 */ 219 private void commitProcess(String taskId, Map<String, Object> variables, 220 String activityId) throws Exception { 221 if (variables == null) { 222 variables = new HashMap<String, Object>(); 223 } 224 // 跳轉節點爲空,默認提交操做 225 if (StringUtil.isNull(activityId)) { 226 taskService.complete(taskId, variables); 227 } else {// 流程轉向操做 228 turnTransition(taskId, activityId, variables); 229 } 230 } 231 232 /** 233 * 清空指定活動節點流向 234 * 235 * @param activityImpl 236 * 活動節點 237 * @return 節點流向集合 238 */ 239 private List<PvmTransition> clearTransition(ActivityImpl activityImpl) { 240 // 存儲當前節點全部流向臨時變量 241 List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>(); 242 // 獲取當前節點全部流向,存儲到臨時變量,而後清空 243 List<PvmTransition> pvmTransitionList = activityImpl 244 .getOutgoingTransitions(); 245 for (PvmTransition pvmTransition : pvmTransitionList) { 246 oriPvmTransitionList.add(pvmTransition); 247 } 248 pvmTransitionList.clear(); 249 250 return oriPvmTransitionList; 251 } 252 253 /** 254 * 還原指定活動節點流向 255 * 256 * @param activityImpl 257 * 活動節點 258 * @param oriPvmTransitionList 259 * 原有節點流向集合 260 */ 261 private void restoreTransition(ActivityImpl activityImpl, 262 List<PvmTransition> oriPvmTransitionList) { 263 // 清空現有流向 264 List<PvmTransition> pvmTransitionList = activityImpl 265 .getOutgoingTransitions(); 266 pvmTransitionList.clear(); 267 // 還原之前流向 268 for (PvmTransition pvmTransition : oriPvmTransitionList) { 269 pvmTransitionList.add(pvmTransition); 270 } 271 } 272 273 /** 274 * 流程轉向操做 275 * 276 * @param taskId 277 * 當前任務ID 278 * @param activityId 279 * 目標節點任務ID 280 * @param variables 281 * 流程變量 282 * @throws Exception 283 */ 284 private void turnTransition(String taskId, String activityId, 285 Map<String, Object> variables) throws Exception { 286 // 當前節點 287 ActivityImpl currActivity = findActivitiImpl(taskId, null); 288 // 清空當前流向 289 List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity); 290 291 // 建立新流向 292 TransitionImpl newTransition = currActivity.createOutgoingTransition(); 293 // 目標節點 294 ActivityImpl pointActivity = findActivitiImpl(taskId, activityId); 295 // 設置新流向的目標節點 296 newTransition.setDestination(pointActivity); 297 298 // 執行轉向任務 299 taskService.complete(taskId, variables); 300 // 刪除目標節點新流入 301 pointActivity.getIncomingTransitions().remove(newTransition); 302 303 // 還原之前流向 304 restoreTransition(currActivity, oriPvmTransitionList); 305 } 306 307 /** 308 * ***************************************************************************************************************************************************<br> 309 * ************************************************以上爲流程轉向操做核心邏輯******************************************************************************<br> 310 * ***************************************************************************************************************************************************<br> 311 */ 312 313 /** 314 * ***************************************************************************************************************************************************<br> 315 * ************************************************如下爲查詢流程駁回節點核心邏輯***************************************************************************<br> 316 * ***************************************************************************************************************************************************<br> 317 */ 318 319 /** 320 * 迭代循環流程樹結構,查詢當前節點可駁回的任務節點 321 * 322 * @param taskId 323 * 當前任務ID 324 * @param currActivity 325 * 當前活動節點 326 * @param rtnList 327 * 存儲回退節點集合 328 * @param tempList 329 * 臨時存儲節點集合(存儲一次迭代過程當中的同級userTask節點) 330 * @return 回退節點集合 331 */ 332 private List<ActivityImpl> iteratorBackActivity(String taskId, 333 ActivityImpl currActivity, List<ActivityImpl> rtnList, 334 List<ActivityImpl> tempList) throws Exception { 335 // 查詢流程定義,生成流程樹結構 336 ProcessInstance processInstance = findProcessInstanceByTaskId(taskId); 337 338 // 當前節點的流入來源 339 List<PvmTransition> incomingTransitions = currActivity 340 .getIncomingTransitions(); 341 // 條件分支節點集合,userTask節點遍歷完畢,迭代遍歷此集合,查詢條件分支對應的userTask節點 342 List<ActivityImpl> exclusiveGateways = new ArrayList<ActivityImpl>(); 343 // 並行節點集合,userTask節點遍歷完畢,迭代遍歷此集合,查詢並行節點對應的userTask節點 344 List<ActivityImpl> parallelGateways = new ArrayList<ActivityImpl>(); 345 // 遍歷當前節點全部流入路徑 346 for (PvmTransition pvmTransition : incomingTransitions) { 347 TransitionImpl transitionImpl = (TransitionImpl) pvmTransition; 348 ActivityImpl activityImpl = transitionImpl.getSource(); 349 String type = (String) activityImpl.getProperty("type"); 350 /** 351 * 並行節點配置要求:<br> 352 * 必須成對出現,且要求分別配置節點ID爲:XXX_start(開始),XXX_end(結束) 353 */ 354 if ("parallelGateway".equals(type)) {// 並行路線 355 String gatewayId = activityImpl.getId(); 356 String gatewayType = gatewayId.substring(gatewayId 357 .lastIndexOf("_") + 1); 358 if ("START".equals(gatewayType.toUpperCase())) {// 並行起點,中止遞歸 359 return rtnList; 360 } else {// 並行終點,臨時存儲此節點,本次循環結束,迭代集合,查詢對應的userTask節點 361 parallelGateways.add(activityImpl); 362 } 363 } else if ("startEvent".equals(type)) {// 開始節點,中止遞歸 364 return rtnList; 365 } else if ("userTask".equals(type)) {// 用戶任務 366 tempList.add(activityImpl); 367 } else if ("exclusiveGateway".equals(type)) {// 分支路線,臨時存儲此節點,本次循環結束,迭代集合,查詢對應的userTask節點 368 currActivity = transitionImpl.getSource(); 369 exclusiveGateways.add(currActivity); 370 } 371 } 372 373 /** 374 * 迭代條件分支集合,查詢對應的userTask節點 375 */ 376 for (ActivityImpl activityImpl : exclusiveGateways) { 377 iteratorBackActivity(taskId, activityImpl, rtnList, tempList); 378 } 379 380 /** 381 * 迭代並行集合,查詢對應的userTask節點 382 */ 383 for (ActivityImpl activityImpl : parallelGateways) { 384 iteratorBackActivity(taskId, activityImpl, rtnList, tempList); 385 } 386 387 /** 388 * 根據同級userTask集合,過濾最近發生的節點 389 */ 390 currActivity = filterNewestActivity(processInstance, tempList); 391 if (currActivity != null) { 392 // 查詢當前節點的流向是否爲並行終點,並獲取並行起點ID 393 String id = findParallelGatewayId(currActivity); 394 if (StringUtil.isNull(id)) {// 並行起點ID爲空,此節點流向不是並行終點,符合駁回條件,存儲此節點 395 rtnList.add(currActivity); 396 } else {// 根據並行起點ID查詢當前節點,而後迭代查詢其對應的userTask任務節點 397 currActivity = findActivitiImpl(taskId, id); 398 } 399 400 // 清空本次迭代臨時集合 401 tempList.clear(); 402 // 執行下次迭代 403 iteratorBackActivity(taskId, currActivity, rtnList, tempList); 404 } 405 return rtnList; 406 } 407 408 /** 409 * 反向排序list集合,便於駁回節點按順序顯示 410 * 411 * @param list 412 * @return 413 */ 414 private List<ActivityImpl> reverList(List<ActivityImpl> list) { 415 List<ActivityImpl> rtnList = new ArrayList<ActivityImpl>(); 416 // 因爲迭代出現重複數據,排除重複 417 for (int i = list.size(); i > 0; i--) { 418 if (!rtnList.contains(list.get(i - 1))) 419 rtnList.add(list.get(i - 1)); 420 } 421 return rtnList; 422 } 423 424 /** 425 * 根據當前節點,查詢輸出流向是否爲並行終點,若是爲並行終點,則拼裝對應的並行起點ID 426 * 427 * @param activityImpl 428 * 當前節點 429 * @return 430 */ 431 private String findParallelGatewayId(ActivityImpl activityImpl) { 432 List<PvmTransition> incomingTransitions = activityImpl 433 .getOutgoingTransitions(); 434 for (PvmTransition pvmTransition : incomingTransitions) { 435 TransitionImpl transitionImpl = (TransitionImpl) pvmTransition; 436 activityImpl = transitionImpl.getDestination(); 437 String type = (String) activityImpl.getProperty("type"); 438 if ("parallelGateway".equals(type)) {// 並行路線 439 String gatewayId = activityImpl.getId(); 440 String gatewayType = gatewayId.substring(gatewayId 441 .lastIndexOf("_") + 1); 442 if ("END".equals(gatewayType.toUpperCase())) { 443 return gatewayId.substring(0, gatewayId.lastIndexOf("_")) 444 + "_start"; 445 } 446 } 447 } 448 return null; 449 } 450 451 /** 452 * 根據流入任務集合,查詢最近一次的流入任務節點 453 * 454 * @param processInstance 455 * 流程實例 456 * @param tempList 457 * 流入任務集合 458 * @return 459 */ 460 private ActivityImpl filterNewestActivity(ProcessInstance processInstance, 461 List<ActivityImpl> tempList) { 462 while (tempList.size() > 0) { 463 ActivityImpl activity_1 = tempList.get(0); 464 HistoricActivityInstance activityInstance_1 = findHistoricUserTask( 465 processInstance, activity_1.getId()); 466 if (activityInstance_1 == null) { 467 tempList.remove(activity_1); 468 continue; 469 } 470 471 if (tempList.size() > 1) { 472 ActivityImpl activity_2 = tempList.get(1); 473 HistoricActivityInstance activityInstance_2 = findHistoricUserTask( 474 processInstance, activity_2.getId()); 475 if (activityInstance_2 == null) { 476 tempList.remove(activity_2); 477 continue; 478 } 479 480 if (activityInstance_1.getEndTime().before( 481 activityInstance_2.getEndTime())) { 482 tempList.remove(activity_1); 483 } else { 484 tempList.remove(activity_2); 485 } 486 } else { 487 break; 488 } 489 } 490 if (tempList.size() > 0) { 491 return tempList.get(0); 492 } 493 return null; 494 } 495 496 /** 497 * 查詢指定任務節點的最新記錄 498 * 499 * @param processInstance 500 * 流程實例 501 * @param activityId 502 * @return 503 */ 504 private HistoricActivityInstance findHistoricUserTask( 505 ProcessInstance processInstance, String activityId) { 506 HistoricActivityInstance rtnVal = null; 507 // 查詢當前流程實例審批結束的歷史節點 508 List<HistoricActivityInstance> historicActivityInstances = historyService 509 .createHistoricActivityInstanceQuery().activityType("userTask") 510 .processInstanceId(processInstance.getId()).activityId( 511 activityId).finished() 512 .orderByHistoricActivityInstanceEndTime().desc().list(); 513 if (historicActivityInstances.size() > 0) { 514 rtnVal = historicActivityInstances.get(0); 515 } 516 517 return rtnVal; 518 } 519 520 /** 521 * *******************************************************************************************************<br> 522 * ********************************以上爲查詢流程駁回節點核心邏輯***********************************************<br> 523 * ********************************************************************************************************<br> 524 */ 525 526 /** 527 * ********************************************************************************<br> 528 * **********************如下爲activiti 核心service 529 * set方法***************************<br> 530 * *********************************************************************************<br> 531 */ 532 public void setFormService(FormService formService) { 533 this.formService = formService; 534 } 535 536 public void setHistoryService(HistoryService historyService) { 537 this.historyService = historyService; 538 } 539 540 public void setRepositoryService(RepositoryService repositoryService) { 541 this.repositoryService = repositoryService; 542 } 543 544 public void setRuntimeService(RuntimeService runtimeService) { 545 this.runtimeService = runtimeService; 546 } 547 548 public void setTaskService(TaskService taskService) { 549 this.taskService = taskService; 550 } 551 552 /** 553 * ********************************************************************************<br> 554 * **********************以上爲activiti 核心service 555 * set方法***************************<br> 556 * *********************************************************************************<br> 557 */ 558 559 /** 560 * ********************************************************************************<br> 561 * **********************如下爲根據 任務節點ID 獲取流程各對象查詢方法**********************<br> 562 * *********************************************************************************<br> 563 */ 564 565 public void setProcessOtherService(ProcessOtherService processOtherService) { 566 this.processOtherService = processOtherService; 567 } 568 569 /** 570 * 根據任務ID得到任務實例 571 * 572 * @param taskId 573 * 任務ID 574 * @return 575 * @throws Exception 576 */ 577 private TaskEntity findTaskById(String taskId) throws Exception { 578 TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId( 579 taskId).singleResult(); 580 if (task == null) { 581 throw new Exception("任務實例未找到!"); 582 } 583 return task; 584 } 585 586 /** 587 * 根據流程實例ID和任務key值查詢全部同級任務集合 588 * 589 * @param processInstanceId 590 * @param key 591 * @return 592 */ 593 private List<Task> findTaskListByKey(String processInstanceId, String key) { 594 return taskService.createTaskQuery().processInstanceId( 595 processInstanceId).taskDefinitionKey(key).list(); 596 } 597 598 /** 599 * 根據任務ID獲取對應的流程實例 600 * 601 * @param taskId 602 * 任務ID 603 * @return 604 * @throws Exception 605 */ 606 private ProcessInstance findProcessInstanceByTaskId(String taskId) 607 throws Exception { 608 // 找到流程實例 609 ProcessInstance processInstance = runtimeService 610 .createProcessInstanceQuery().processInstanceId( 611 findTaskById(taskId).getProcessInstanceId()) 612 .singleResult(); 613 if (processInstance == null) { 614 throw new Exception("流程實例未找到!"); 615 } 616 return processInstance; 617 } 618 619 /** 620 * 根據任務ID獲取流程定義 621 * 622 * @param taskId 623 * 任務ID 624 * @return 625 * @throws Exception 626 */ 627 private ProcessDefinitionEntity findProcessDefinitionEntityByTaskId( 628 String taskId) throws Exception { 629 // 取得流程定義 630 ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService) 631 .getDeployedProcessDefinition(findTaskById(taskId) 632 .getProcessDefinitionId()); 633 634 if (processDefinition == null) { 635 throw new Exception("流程定義未找到!"); 636 } 637 638 return processDefinition; 639 } 640 641 /** 642 * 根據任務ID和節點ID獲取活動節點 <br> 643 * 644 * @param taskId 645 * 任務ID 646 * @param activityId 647 * 活動節點ID <br> 648 * 若是爲null或"",則默認查詢當前活動節點 <br> 649 * 若是爲"end",則查詢結束節點 <br> 650 * 651 * @return 652 * @throws Exception 653 */ 654 private ActivityImpl findActivitiImpl(String taskId, String activityId) 655 throws Exception { 656 // 取得流程定義 657 ProcessDefinitionEntity processDefinition = findProcessDefinitionEntityByTaskId(taskId); 658 659 // 獲取當前活動節點ID 660 if (StringUtil.isNull(activityId)) { 661 activityId = findTaskById(taskId).getTaskDefinitionKey(); 662 } 663 664 // 根據流程定義,獲取該流程實例的結束節點 665 if (activityId.toUpperCase().equals("END")) { 666 for (ActivityImpl activityImpl : processDefinition.getActivities()) { 667 List<PvmTransition> pvmTransitionList = activityImpl 668 .getOutgoingTransitions(); 669 if (pvmTransitionList.isEmpty()) { 670 return activityImpl; 671 } 672 } 673 } 674 675 // 根據節點ID,獲取對應的活動節點 676 ActivityImpl activityImpl = ((ProcessDefinitionImpl) processDefinition) 677 .findActivity(activityId); 678 679 return activityImpl; 680 } 681 682 /** 683 * ********************************************************************************<br> 684 * **********************以上爲根據 任務節點ID 獲取流程各對象查詢方法**********************<br> 685 * *********************************************************************************<br> 686 */ 687 }