java调用Activiti实现二次开发
activiti发展到现在,发布版本已经到7了。Activiti项目是一项新的基于Apache许可的开源BPM平台,从基础开始构建,旨在提供支持新的BPMN 2.0标准,包括支持对象管理组(OMG),可以定义流程、执行流程并以不同方式对其实现运行。
一、activiti数据库表结构说明
表名默认以“ACT_”开头,并且表名的第二部分用两个字母表明表的用例,而这个用例也基本上跟Service API匹配。
ACT_GE_* : “GE”代表“General”(通用),用在各种情况下;
ACT_HI_* : “HI”代表“History”(历史),这些表中保存的都是历史数据,比如执行过的流程实例、变量、任务,等等。Activit默认提供了4种历史级别:
ACT_RE_* : “RE”代表“Repository”(仓库),这些表中保存一些‘静态’信息,如流程定义和流程资源(如图片、规则等);
ACT_RU_* : “RU”代表“Runtime”(运行时),这些表中保存一些流程实例、用户任务、变量等的运行时数据。Activiti只保存流程实例在执行过程中的运行时数据,并且当流程结束后会立即移除这些数据;
表分类 | 表名称 | 表含义 |
资源库流程规则表 | act_re_deployment | 部署信息表 |
act_re_model | 流程设计模型部署表 | |
act_re_procdef | 流程定义数据表 | |
流程历史记录 | act_hi_actinst | 历史的流程实例 |
act_hi_attachment | 历史的流程附件 | |
act_hi_comment | 历史的说明性信息 | |
act_hi_detail | 历史的流程运行中的细节信息 | |
act_hi_identitylink | 历史的流程运行过程中用户关系 | |
act_hi_procinst | 历史的流程实例 | |
act_hi_taskinst | 历史的任务实例 | |
act_hi_varinst | 历史的流程运行中的变量信息 | |
流程运行实例记录 | act_ru_deadletter_job | 执行失败任务表 |
act_ru_integration | 运行时流程人员表,主要存储任务节点与参与者的相关信息 | |
act_ru_event_subscr | 运行时事件 | |
act_ru_execution | 运行时流程执行实例 | |
act_ru_identitylink | 运行时用户关系信息 | |
act_ru_job | 运行时作业 | |
act_ru_suspended_job | 运行时暂停任务 | |
act_ru_task | 运行时任务 | |
act_ru_timer_job | 运行时定时任务 | |
act_ru_variable | 运行时变量表 | |
通用数据表 | act_ge_bytearray | 二进制数据表 |
act_ge_property | 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录 |
二、activiti提供服务的七大对象
RepositoryService: Activiti 中每一个不同版本的业务流程的定义都需要使用一些定义文件,部署文件和支持数据 ( 例如 BPMN2.0 XML 文件,表单定义文件,流程定义图像文件等 ),这些文件都存储在 Activiti 内建的 Repository 中。Repository Service 提供了对 repository 的存取服务。
RuntimeService: 在 Activiti 中,每当一个流程定义被启动一次之后,都会生成一个相应的流程对象实例。Runtime Service 提供了启动流程、查询流程实例、设置获取流程实例变量等功能。此外它还提供了对流程部署,流程定义和流程实例的存取服务。
TaskService: 在 Activiti 中业务流程定义中的每一个执行节点被称为一个 Task,对流程中的数据存取,状态变更等操作均需要在 Task 中完成。Task Service 提供了对用户 Task 和 Form 相关的操作。它提供了运行时任务查询、领取、完成、删除以及变量设置等功能。
IdentityService: Activiti 中内置了用户以及组管理的功能,必须使用这些用户和组的信息才能获取到相应的 Task。Identity Service 提供了对 Activiti 系统中的用户和组的管理功能。
ManagementService: Management Service 提供了对 Activiti 流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于 Activiti 系统的日常维护。
HistoryService: Activiti 中的流程和状态 Task 均可以关联业务相关的数据。通过使用 Form Service 可以存取启动和完成任务所需的表单数据并且根据需要来渲染表单。
FormService: Activiti 中的流程和状态 Task 均可以关联业务相关的数据。通过使用 Form Service 可以存取启动和完成任务所需的表单数据并且根据需要来渲染表单。
三、java封装实例
1、前端界面效果图
2、二次开发类图
3、代码展示
如下是具体实现的类信息,当前实例封装的是通过具体人和人员角色两个维度来实现业务节点审核,要实现业务功能只需要实现BaseBusinessActivitiOption类的方法,并扩充业务实现就好。
1)NumrangeEntity 审核流条件表达式类,用于记录审核流条件分支的条件信息
1 public class NumrangeEntity { 2 3 public NumrangeEntity(){} 4 5 public NumrangeEntity(String expression){ 6 expression = expression.replace("${","").replace("}",""); 7 if(expression.contains("&&")){ 8 String[] branchExpression = expression.split("&&"); 9 String[] params = expressionBackwardAnalysis(branchExpression[0]); 10 this.variable = params[0]; 11 this.minValue = Double.parseDouble(params[2]); 12 params = expressionBackwardAnalysis(branchExpression[1]); 13 this.maxValue = Double.parseDouble(params[2]); 14 this.op = "6"; 15 }else{ 16 String[] params = expressionBackwardAnalysis(expression); 17 this.variable = params[0]; 18 this.op = params[1]; 19 this.value = Double.parseDouble(params[2]); 20 } 21 22 getConditionName(); 23 } 24 25 private String[] expressionBackwardAnalysis(String expression){ 26 String[] params = expression.split(" "); 27 switch(params[1]){ 28 case "==": 29 params[1] = "1"; 30 break; 31 case ">": 32 params[1] = "2"; 33 break; 34 case "<": 35 params[1] = "3"; 36 break; 37 case ">=": 38 params[1] = "4"; 39 break; 40 case "<=": 41 params[1] = "5"; 42 break; 43 } 44 45 return params; 46 } 47 48 /** 49 * 操作类型:1-等于;2-大于;3-小于;4-大于等于;5-小于等于;6-介于 50 */ 51 private String op; 52 53 /** 54 *比较值 55 */ 56 private double value; 57 58 /** 59 * 区间最小值 60 */ 61 private double minValue; 62 63 /** 64 * 区间最大值 65 */ 66 private double maxValue; 67 68 private String variable; 69 70 private String conditionName; 71 72 public String getOp() { 73 return op; 74 } 75 76 public String getExpression(){ 77 StringBuffer expression = new StringBuffer(); 78 expression.append("${"); 79 switch(op){ 80 case "1#等于": 81 expression.append(variable + " == " + value); 82 break; 83 case "2#大于": 84 expression.append(variable + " > " + value); 85 break; 86 case "3#小于": 87 expression.append(variable + " < " + value); 88 break; 89 case "4#大于等于": 90 expression.append(variable + " >= " + value); 91 break; 92 case "5#小于等于": 93 expression.append(variable + " <= " + value); 94 break; 95 case "6#介于": 96 expression.append(variable + " > " + minValue + "&&" + variable + " < " + maxValue); 97 break; 98 } 99 100 expression.append("}"); 101 102 return expression.toString(); 103 } 104 105 public void getConditionName(){ 106 StringBuffer name = new StringBuffer(); 107 name.append(Variable.valueOf(variable.toUpperCase()).getText()); 108 109 switch (op){ 110 case "1": 111 name.append("等于"); 112 op = "1#等于"; 113 break; 114 case "2": 115 name.append("大于"); 116 op = "2#大于"; 117 break; 118 case "3": 119 name.append("小于"); 120 op = "3#小于"; 121 break; 122 case "4": 123 name.append("大于等于"); 124 op = "4#大于等于"; 125 break; 126 case "5": 127 name.append("小于等于"); 128 op = "5#小于等于"; 129 break; 130 case "6": 131 name.append("介于"); 132 op = "6#介于"; 133 } 134 if(op.equals("6#介于")){ 135 name.append(minValue); 136 name.append(Variable.valueOf(variable.toUpperCase()).getUnit()); 137 name.append("-"); 138 name.append(maxValue); 139 }else{ 140 name.append(value); 141 } 142 143 name.append(Variable.valueOf(variable.toUpperCase()).getUnit()); 144 145 conditionName = name.toString(); 146 } 147 148 public void setOp(String op) { 149 this.op = op; 150 } 151 152 public double getValue() { 153 return value; 154 } 155 156 public void setValue(double value) { 157 this.value = value; 158 } 159 160 public double getMinValue() { 161 return minValue; 162 } 163 164 public void setMinValue(double minValue) { 165 this.minValue = minValue; 166 } 167 168 public double getMaxValue() { 169 return maxValue; 170 } 171 172 public void setMaxValue(double maxValue) { 173 this.maxValue = maxValue; 174 } 175 176 public String getVariable() { 177 return variable; 178 } 179 180 public void setVariable(String variable) { 181 this.variable = variable; 182 } 183 184 enum Variable{ 185 186 CONTRACTAMOUNT("contractAmount","合同金额","万元"); 187 Variable(String name,String text,String unit){ 188 this.name = name; 189 this.text = text; 190 this.unit = unit; 191 } 192 193 private String name; 194 private String text; 195 private String unit; 196 197 public String getName(){ 198 return name; 199 } 200 201 public String getText(){ 202 return text; 203 } 204 205 public String getUnit(){ 206 return unit; 207 } 208 } 209 }
2)TaskNodeEntity 审核流任务节点类,用于记录审核节点信息
1 public class TaskNodeEntity { 2 3 public TaskNodeEntity(){} 4 5 public TaskNodeEntity(String nodeType,String nodeTitleName,String nodeTitle,int order){ 6 this.nodeType = nodeType; 7 this.nodeTitle = nodeTitle; 8 this.nodeTitleName = nodeTitleName; 9 this.order = order; 10 } 11 12 /** 13 * 任务节点类型:role-角色;people-具体人 14 */ 15 private String nodeType; 16 17 /** 18 * 任务节点标题名称:角色名称/用户名称 19 */ 20 private String nodeTitleName; 21 22 /** 23 * 任务节点标题:角色编码/用户ID 24 */ 25 private String nodeTitle; 26 27 /** 28 * 任务节点位置 29 */ 30 private int order; 31 32 public String getNodeType() { 33 return nodeType; 34 } 35 36 public void setNodeType(String nodeType) { 37 this.nodeType = nodeType; 38 } 39 40 public String getNodeTitleName() { 41 return nodeTitleName; 42 } 43 44 public void setNodeTitleName(String nodeTitleName) { 45 this.nodeTitleName = nodeTitleName; 46 } 47 48 public String getNodeTitle() { 49 return nodeTitle; 50 } 51 52 public void setNodeTitle(String nodeTitle) { 53 this.nodeTitle = nodeTitle; 54 } 55 56 public int getOrder() { 57 return order; 58 } 59 60 public void setOrder(int order) { 61 this.order = order; 62 } 63 64 @Override 65 public boolean equals(Object obj) { 66 if(this == obj){ 67 return true; 68 } 69 70 if(obj == null){ 71 return false; 72 } 73 74 if(obj instanceof TaskNodeEntity){ 75 TaskNodeEntity taskNodeEntity = (TaskNodeEntity) obj; 76 if(equalsStr(this.nodeType,taskNodeEntity.getNodeType()) && equalsStr(this.nodeTitle,taskNodeEntity.getNodeTitle())){ 77 return true; 78 } 79 } 80 return false; 81 } 82 83 @Override 84 public int hashCode() { 85 return Objects.hash(this.nodeType,this.nodeTitle); 86 } 87 88 private boolean equalsStr(String str1, String str2){ 89 if(StringUtils.isEmpty(str1) && StringUtils.isEmpty(str2)){ 90 return true; 91 } 92 if(!StringUtils.isEmpty(str1) && str1.equals(str2)){ 93 return true; 94 } 95 return false; 96 } 97 }
3)RuleEntity 审核流子流程信息类
1 public class RuleEntity { 2 3 public RuleEntity(){}; 4 5 public RuleEntity(String ruleName,String ruleType,NumrangeEntity numrangeitem){ 6 this.ruleName = ruleName; 7 this.ruleType = ruleType; 8 this.numrangeitem = numrangeitem; 9 } 10 11 /** 12 * 任务节点 13 */ 14 private List<TaskNodeEntity> taskNodes; 15 16 /** 17 * 规则名称名称 18 */ 19 private String ruleName; 20 21 /** 22 * 规则类型:default-默认;condition-条件 23 */ 24 private String ruleType; 25 26 /** 27 * 条件参数 28 */ 29 private NumrangeEntity numrangeitem; 30 31 public List<TaskNodeEntity> getTaskNodes() { 32 if(null == taskNodes){ 33 return taskNodes = new ArrayList<TaskNodeEntity>(); 34 } 35 return taskNodes; 36 } 37 38 public void setTaskNodes(List<TaskNodeEntity> taskNodes) { 39 this.taskNodes = taskNodes; 40 } 41 42 public String getRuleName() { 43 return ruleName; 44 } 45 46 public void setRuleName(String ruleName) { 47 this.ruleName = ruleName; 48 } 49 50 public String getRuleType() { 51 return ruleType; 52 } 53 54 public void setRuleType(String ruleType) { 55 this.ruleType = ruleType; 56 } 57 58 public NumrangeEntity getNumrangeitem() { 59 return numrangeitem; 60 } 61 62 public void setNumrangeitem(NumrangeEntity numrangeitem) { 63 this.numrangeitem = numrangeitem; 64 } 65 }
4)ProcessEntity 审核流全流程信息
1 public class ProcessEntity { 2 3 /** 4 * 子流程集合 5 */ 6 private List<RuleEntity> rules; 7 8 /** 9 * 流程类型:认定、终止合同、废标、建议删除 10 */ 11 private String processType; 12 13 /** 14 * 流程类型名称 15 */ 16 private String processTypeName; 17 18 /** 19 * 所属机构名称 20 */ 21 private String orgName; 22 23 /** 24 * 所属机构编码 25 */ 26 private String orgId; 27 28 public List<RuleEntity> getRules() { 29 if(null == rules){ 30 return rules = new ArrayList<RuleEntity>(); 31 } 32 return rules; 33 } 34 35 public void setRules(List<RuleEntity> rules) { 36 this.rules = rules; 37 } 38 39 public String getProcessType() { 40 return processType; 41 } 42 43 public void setProcessType(String processType) { 44 this.processType = processType; 45 } 46 47 public String getProcessTypeName() { 48 return processTypeName; 49 } 50 51 public void setProcessTypeName(String processTypeName) { 52 this.processTypeName = processTypeName; 53 } 54 55 public String getOrgName() { 56 return orgName; 57 } 58 59 public void setOrgName(String orgName) { 60 this.orgName = orgName; 61 } 62 63 public String getOrgId() { 64 return orgId; 65 } 66 67 public void setOrgId(String orgId) { 68 this.orgId = orgId; 69 } 70 }
5)ApplyDomain 审核流任务节点处理结果实体;ProcessType 审核流类型枚举
1 public class ApplyDomain extends PagingDomain{ 2 3 @TableField(exist = false) 4 private String taskId; 5 6 @TableField(exist = false) 7 private String currentUserCode; 8 9 /** 10 * 审核状态:init-审核中;pass-通过;fail-不通过 11 */ 12 @TableField("examination_status") 13 private String examinationStatus; 14 15 public String getTaskId() { 16 return taskId; 17 } 18 19 public void setTaskId(String taskId) { 20 this.taskId = taskId; 21 } 22 23 public String getCurrentUserCode() { 24 return currentUserCode; 25 } 26 27 public void setCurrentUserCode(String currentUserCode) { 28 this.currentUserCode = currentUserCode; 29 } 30 31 public String getExaminationStatus() { 32 return examinationStatus; 33 } 34 35 public void setExaminationStatus(String examinationStatus) { 36 this.examinationStatus = examinationStatus; 37 } 38 }
1 public enum ProcessType { 2 RENDING("rending","项目认定"), 3 SHANCHU("shanchu","建议删除"), 4 PROJECTADD("projectAdd","项目添加"), 5 PROJECTEDITOR("projectEditor","项目编辑"), 6 ZHONGZHI("zhongzhi","项目中止"), 7 YICHANG("yichang","项目异常"), 8 YIJIAO("yijiao","项目移交"); 9 10 11 ProcessType(String type,String typeName){ 12 this.type = type; 13 this.typeName = typeName; 14 } 15 16 private String type; 17 18 private String typeName; 19 20 public String getType() { 21 return type; 22 } 23 24 public String getTypeName() { 25 return typeName; 26 } 27 }
6)ActivitiOption 审核流流程操作类,提供了七大服务类的操作
1 @Component 2 public class ActivitiOption { 3 4 @Autowired 5 private RepositoryService repositoryService; 6 7 @Autowired 8 private RuntimeService runtimeService; 9 10 @Autowired 11 private HistoryService historyService; 12 13 @Autowired 14 private TaskService taskService; 15 16 protected void findAllProcess(Set<String> set){ 17 List<ProcessDefinition> definitions = repositoryService 18 .createProcessDefinitionQuery() 19 .processDefinitionKeys(set) 20 .latestVersion() 21 .orderByProcessDefinitionVersion() 22 .desc() 23 .list(); 24 } 25 26 /** 27 * Description:获取流程定义 28 * Param: 29 * Return: 30 * Auther: cymiao 31 * Date: 2019/9/26 14:01 32 */ 33 protected ProcessEntity findProcess(String orgId,String processType,String processTypeName){ 34 //通过流程Key获取流程定义对象 35 ProcessDefinition definition = repositoryService 36 .createProcessDefinitionQuery() 37 .processDefinitionKey(getProcessKey(orgId, processType)) 38 .latestVersion() 39 .singleResult(); 40 41 if(null == definition){ 42 throw new BusinessBaseException(new BusinessExceptionDesc("3002001", BusinessExceptionDesc.SHOW_TYPE.ERROR,"当前查询的机构没有定义" + processTypeName + "类型的审核流")); 43 } 44 45 //获取流程下的所有节点 46 List<FlowElement> flowElements = (List<FlowElement>) repositoryService 47 .getBpmnModel(definition.getId()) 48 .getProcesses() 49 .get(0) 50 .getFlowElements(); 51 52 //反向解析 53 ProcessEntity processInfo = new ProcessEntity(); 54 bpmnBackwardAnalysis(flowElements,processInfo); 55 return processInfo; 56 } 57 58 /** 59 * Description:反向解析BpmnModel 60 * Param: 61 * Return: 62 * Auther: cymiao 63 * Date: 2019/9/26 14:02 64 */ 65 protected void bpmnBackwardAnalysis(List<FlowElement> flowElements,ProcessEntity processInfo){ 66 for (FlowElement flowElement : flowElements){ 67 if(flowElement instanceof SequenceFlow){ 68 FlowElement sourceFlowElement = ((SequenceFlow) flowElement).getSourceFlowElement(); 69 if(sourceFlowElement.getId().equals("start")){ 70 FlowElement targetFlowElement = ((SequenceFlow) flowElement).getTargetFlowElement(); 71 //开始节点的下一个节点,如果为网关则是条件网关 72 if(targetFlowElement instanceof ExclusiveGateway){ 73 ExclusiveGateway gateway = (ExclusiveGateway) targetFlowElement; 74 List<SequenceFlow> flows = gateway.getOutgoingFlows(); 75 for(SequenceFlow flow : flows){ 76 //${money > 300} 77 String conditionExpression = flow.getConditionExpression(); 78 79 //分支流程 80 RuleEntity rule = null; 81 if(flow.getId().equals(gateway.getDefaultFlow())){ 82 rule = new RuleEntity(flow.getName(),"default",null); 83 }else{ 84 //分支条件 85 NumrangeEntity numrangeEntity = new NumrangeEntity(conditionExpression); 86 rule = new RuleEntity(flow.getName(),"condition",numrangeEntity); 87 } 88 89 90 processInfo.getRules().add(rule); 91 92 sequenceFlowBackwardAnalysis(flow.getTargetFlowElement(),rule,1); 93 } 94 }/* 95 //开始节点的下一个节点是任务节点 96 else if(targetFlowElement instanceof UserTask){ 97 RuleEntity rule = new RuleEntity(flowElement.getName(),"",null); 98 sequenceFlowBackwardAnalysis(targetFlowElement,rule,1); 99 }*/ 100 } 101 break; 102 } 103 } 104 } 105 106 /** 107 * Description:反向解析任务节点 108 * Param: 109 * Return: 110 * Auther: cymiao 111 * Date: 2019/9/26 14:02 112 */ 113 protected void sequenceFlowBackwardAnalysis(FlowElement flowElement,RuleEntity rule,int order){ 114 if(flowElement instanceof UserTask){ 115 UserTask userTask = (UserTask) flowElement; 116 String taskId = userTask.getId(); 117 if(taskId.lastIndexOf("-") > 0){ 118 String suffiz = taskId.substring(taskId.lastIndexOf("-")); 119 taskId = taskId.replace(suffiz,""); 120 } 121 122 //节点类型 123 String nodeType = taskId.contains("people") ? "people" : "role"; 124 125 //节点标题 126 String nodeTitle = taskId.replace(nodeType,""); 127 128 //节点实例 129 TaskNodeEntity nodeEntity = new TaskNodeEntity(nodeType,userTask.getName(),nodeTitle,order); 130 rule.getTaskNodes().add(nodeEntity); 131 132 //下一个节点对象 133 FlowElement nextFlowElement1 = userTask 134 .getOutgoingFlows() 135 .get(0) 136 .getTargetFlowElement(); 137 138 //下一个节点存在,并且是网关节点 139 if(null != nextFlowElement1 && nextFlowElement1 instanceof ExclusiveGateway){ 140 ExclusiveGateway switchGateway = (ExclusiveGateway)nextFlowElement1; 141 List<SequenceFlow> flows = switchGateway.getOutgoingFlows(); 142 for (SequenceFlow flow : flows){ 143 //下一个任务节点 144 if(flow.getTargetFlowElement() instanceof UserTask){ 145 sequenceFlowBackwardAnalysis(flow.getTargetFlowElement(),rule, ++order); 146 } 147 } 148 } 149 //下一个节点是结束事件节点 150 else if(null != nextFlowElement1 && nextFlowElement1 instanceof EndEvent){ 151 return; 152 } 153 } 154 } 155 156 /** 157 * Description:获取子流程的历史任务 158 * Param: 159 * Return: 160 * Auther: cymiao 161 * Date: 2019/9/25 17:34 162 */ 163 protected List<HistoricActivityInstance> findProcessHistoryByStartTime(String processInstanceId){ 164 List<HistoricActivityInstance> his = historyService 165 .createHistoricActivityInstanceQuery() 166 .processInstanceId(processInstanceId) 167 .orderByHistoricActivityInstanceStartTime().asc().list(); 168 return his; 169 } 170 171 /** 172 * Description:发布部署 173 * Param: 174 * Return: 175 * Auther: cymiao 176 * Date: 2019/9/17 19:43 177 */ 178 protected void deployDeployment(ProcessEntity processInfo){ 179 BpmnModel bpmnModel = new BpmnModel(); 180 bpmnModel.addProcess(createProcess(processInfo)); 181 182 //验证Bpmn文件的可用性 183 ProcessValidatorFactory processValidatorFactory = new ProcessValidatorFactory(); 184 ProcessValidator processValidator = processValidatorFactory.createDefaultProcessValidator(); 185 List<ValidationError> validate = processValidator.validate(bpmnModel); 186 if(validate.size()>=1){ 187 for (ValidationError validationError : validate) { 188 System.out.println(validationError.getProblem()); 189 throw new BusinessBaseException(new BusinessExceptionDesc("", BusinessExceptionDesc.SHOW_TYPE.ERROR,"配置项错误,审核流不可用")); 190 } 191 } 192 193 BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter(); 194 try { 195 String e = new String(bpmnXMLConverter.convertToXML(bpmnModel), "UTF-8"); 196 System.out.println(e); 197 } catch (UnsupportedEncodingException var5) { 198 throw new ActivitiException("Error while transforming BPMN model to xml: not UTF-8 encoded", var5); 199 } 200 201 //创建一个部署对象 202 repositoryService.createDeployment() 203 .addBpmnModel("org" + processInfo.getOrgId() + processInfo.getProcessType() + ".bpmn",bpmnModel) 204 .name(processInfo.getOrgName() + processInfo.getProcessTypeName()) 205 .deploy(); 206 } 207 208 /** 209 * Description:创建流程实例 210 * Param: 211 * Return: 212 * Auther: cymiao 213 * Date: 2019/9/19 18:50 214 */ 215 protected String startProcessInstance(String orgId,String processType,String businessId,Map<String,Object> variables){ 216 String processInstanceKey = "org" + orgId + processType; 217 ProcessInstance pi = runtimeService 218 .startProcessInstanceByKey(processInstanceKey,processType + "-" + businessId,variables); 219 return pi.getProcessInstanceId(); 220 } 221 222 /** 223 * Description:任务审核结束 224 * Param: 225 * Return: 226 * Auther: cymiao 227 * Date: 2019/9/20 9:39 228 */ 229 protected void taskComplete(String taskid,String examineUser, Map<String,Object> variables){ 230 taskService.claim(taskid, examineUser); 231 taskService.complete(taskid, variables); 232 } 233 234 /** 235 * Description:通过任务Id获取流程实例Id 236 * Param: 237 * Return: 238 * Auther: cymiao 239 * Date: 2019/9/24 18:18 240 */ 241 protected String findProcessInstanceIdByTaskId(String taskid){ 242 String processInstanceId = taskService 243 .createTaskQuery() 244 .taskId(taskid) 245 .singleResult() 246 .getProcessInstanceId(); 247 return processInstanceId; 248 } 249 250 /** 251 * Description:通过角色查询某一类型的待办任务 252 * Param: 253 * Return: 254 * Auther: cymiao 255 * Date: 2019/9/20 15:23 256 */ 257 protected List<Task> findRoleTasks(String processKey,String roleCode){ 258 List<Task> tasks = taskService 259 .createTaskQuery() 260 .processDefinitionKey(processKey) 261 .taskCandidateGroup(roleCode) 262 .list(); 263 return tasks; 264 } 265 266 /** 267 * Description:通过角色查询某一类型的待办任务的数量 268 * Param: 269 * Return: 270 * Auther: cymiao 271 * Date: 2019/9/20 15:24 272 */ 273 protected int findRoleTasksCount(String processKey,String roleCode){ 274 int totaltask = (int)taskService.createTaskQuery().processDefinitionKey(processKey).taskCandidateGroup(roleCode).count(); 275 return totaltask; 276 } 277 278 /** 279 * Description:通过角色查询所有的待办任务 280 * Param: 281 * Return: 282 * Auther: cymiao 283 * Date: 2019/9/20 15:23 284 */ 285 protected List<Task> findRoleTasks(String roleCode,int firstrow,int rowCount){ 286 List<Task> tasks = taskService 287 .createTaskQuery() 288 .taskCandidateGroup(roleCode) 289 .listPage(firstrow, rowCount); 290 return tasks; 291 } 292 293 /** 294 * Description:通过角色查询所有的待办任务的数量 295 * Param: 296 * Return: 297 * Auther: cymiao 298 * Date: 2019/9/20 15:25 299 */ 300 protected int findRoleTasksCount(String roleCode){ 301 int totaltask = (int)taskService 302 .createTaskQuery() 303 .taskCandidateGroup(roleCode) 304 .count(); 305 return totaltask; 306 } 307 308 /** 309 * Description:通过用户ID查询某一类型的待办任务 310 * Param: 311 * Return: 312 * Auther: cymiao 313 * Date: 2019/9/20 15:26 314 */ 315 protected List<Task> findUserTasks(String processKey,String userCode){ 316 List<Task> tasks = taskService 317 .createTaskQuery() 318 .processDefinitionKey(processKey) 319 .taskCandidateUser(userCode) 320 .list(); 321 return tasks; 322 } 323 324 protected List<Task> findUserTasks(List<String> processKeys,String userCode){ 325 List<Task> tasks = taskService 326 .createTaskQuery() 327 .processDefinitionKeyIn(processKeys) 328 .taskCandidateUser(userCode) 329 .list(); 330 return tasks; 331 } 332 333 /** 334 * Description:通过用户ID查询某一类型的待办任务的数量 335 * Param: 336 * Return: 337 * Auther: cymiao 338 * Date: 2019/9/20 15:27 339 */ 340 protected int findUserTasksCount(String processKey,String userCode){ 341 int totaltask = (int)taskService 342 .createTaskQuery() 343 .processDefinitionKey(processKey) 344 .taskCandidateUser(userCode) 345 .count(); 346 return totaltask; 347 } 348 349 /** 350 * Description:通过用户ID查询所有的待办任务 351 * Param: 352 * Return: 353 * Auther: cymiao 354 * Date: 2019/9/20 15:28 355 */ 356 protected List<Task> findUserTasks(String userCode){ 357 List<Task> tasks = taskService 358 .createTaskQuery() 359 .taskCandidateUser(userCode) 360 .list(); 361 return tasks; 362 } 363 364 /** 365 * Description:通过用户ID查询所有的待办任务数量 366 * Param: 367 * Return: 368 * Auther: cymiao 369 * Date: 2019/9/20 15:29 370 */ 371 protected int findUserTasksCount(String userCode){ 372 int totaltask = (int)taskService 373 .createTaskQuery() 374 .taskCandidateUser(userCode) 375 .count(); 376 return totaltask; 377 } 378 379 /** 380 * Description:获取流程Id 381 * Param: 382 * Return: 383 * Auther: cymiao 384 * Date: 2019/9/20 16:00 385 */ 386 protected String getProcessKey(String orgId,String processType){ 387 return "org" + orgId + processType; 388 } 389 390 /** 391 * Description:通过工作流实例ID获取业务主键 392 * Param: 393 * Return: 394 * Auther: cymiao 395 * Date: 2019/9/20 16:02 396 */ 397 public String findBusinesskeyByProcessInstanceId(String processInstanceId){ 398 String businesskey = runtimeService. 399 createProcessInstanceQuery() 400 .processInstanceId(processInstanceId) 401 .singleResult() 402 .getBusinessKey(); 403 return businesskey; 404 } 405 406 /** 407 * Description:创建流程 408 * Param: 409 * Return: 410 * Auther: cymiao 411 * Date: 2019/9/17 19:43 412 */ 413 protected Process createProcess(ProcessEntity processInfo){ 414 415 FlowElement previousFlowElement = null; 416 Process process = new Process(); 417 418 //ID:org + 组织机构ID + 流程类型 419 process.setId("org" + processInfo.getOrgId() + processInfo.getProcessType()); 420 421 //NAME:组织机构名称 + 流程类型名称 422 process.setName(processInfo.getOrgName() + processInfo.getProcessTypeName()); 423 424 //添加开始事件 425 FlowElement startEvent = createStartEvent(); 426 process.addFlowElement(startEvent); 427 428 //创建异常结束事件 429 FlowElement abnormalEndEvent = createEndEvent("abnormalEnd","异常结束",true); 430 process.addFlowElement(abnormalEndEvent); 431 432 //添加结束事件 433 FlowElement endEvent = createEndEvent("end","结束",false); 434 process.addFlowElement(endEvent); 435 436 List<RuleEntity> rules = processInfo.getRules(); 437 if(null == rules || rules.isEmpty()){ 438 throw new BusinessBaseException(new BusinessExceptionDesc("", BusinessExceptionDesc.SHOW_TYPE.ERROR,"审核流程不能空")); 439 }else{ 440 List<TaskNodeEntity> taskNodes = null; 441 //审核通过和不通过判断表达式 442 String examinationPass = "${examinationStatus == 'pass'}"; 443 String examinationNotPass = "${examinationStatus == 'fail'}"; 444 445 //创建条件网关 446 ExclusiveGateway conditionExclusiveGateway = null; 447 process.addFlowElement(conditionExclusiveGateway = createExclusiveGateway("条件判断网关","condition")); 448 449 //创建连线:流程开始节点到条件网关的连线 450 SequenceFlow sequenceFlow = genarateSequenceFlow("flow1","网关",startEvent.getId(),conditionExclusiveGateway.getId(),"",process); 451 process.addFlowElement(sequenceFlow); 452 conditionExclusiveGateway.getOutgoingFlows().add(sequenceFlow); 453 454 for (int i = 0; i < rules.size(); i++){ 455 previousFlowElement = conditionExclusiveGateway; 456 RuleEntity rule = rules.get(i); 457 458 //创建子流程 459 taskNodes = rule.getTaskNodes(); 460 461 //规则重排序 462 Collections.sort(taskNodes, new Comparator<TaskNodeEntity>() { 463 @Override 464 public int compare(TaskNodeEntity o1, TaskNodeEntity o2) { 465 if(o1.getOrder() > o2.getOrder()){ 466 return 1; 467 }else{ 468 return -1; 469 } 470 } 471 }); 472 UserTask userTask = null; 473 for (int j = 0; j < taskNodes.size(); j++){ 474 TaskNodeEntity taskNode = taskNodes.get(j); 475 String taskId = taskNode.getNodeType() + taskNode.getNodeTitle() + "-" + rule.getRuleType() + i; 476 477 //创建任务 478 userTask = createUserTask(taskNode.getNodeTitleName(),taskId,taskNode.getNodeType(),taskNode.getNodeTitle()); 479 process.addFlowElement(userTask); 480 481 //创建通过和不通过分支网关 482 ExclusiveGateway switchGateway = createExclusiveGateway("分支网关","switchGateway" + (i + 1) + (j + 1)); 483 process.addFlowElement(switchGateway); 484 485 //创建当前节点到分支网关的连线 486 process.addFlowElement(genarateSequenceFlow("flow1-" + (i + 1) + (j + 1),"到达分支",taskId,switchGateway.getId(),"",process)); 487 488 //创建连线:上一个节点到当前节点的连线 489 if(j == 0){ 490 //条件网关到子流程第一个任务节点的连线 491 if("default".equalsIgnoreCase(rule.getRuleType())){ 492 process.addFlowElement(genarateSequenceFlow("flow-" + (i + 1) + (j + 1),rule.getRuleName(), 493 previousFlowElement.getId(),taskId,"",process)); 494 conditionExclusiveGateway.setDefaultFlow("flow-" + (i + 1) + (j + 1)); 495 }else if("condition".equalsIgnoreCase(rule.getRuleType())){ 496 process.addFlowElement(genarateSequenceFlow("flow-" + (i + 1) + (j + 1),rule.getRuleName(), 497 previousFlowElement.getId(),taskId,rule.getNumrangeitem().getExpression(),process)); 498 } 499 500 }/*else if(j == 0){ 501 //流程开始节点到第一个任务节点的连线 502 process.addFlowElement(genarateSequenceFlow("flow-" + (i + 1) + (j + 1),"开始", 503 previousFlowElement.getId(),taskId,"",process)); 504 }*/else if(j > 0){ 505 //上一个任务节点分支网关审核通过到当前任务节点连线 506 sequenceFlow = genarateSequenceFlow("flow2-" +(i + 1) + (j + 1),"通过", 507 previousFlowElement.getId(),taskId,examinationPass,process); 508 process.addFlowElement(sequenceFlow); 509 ((ExclusiveGateway)previousFlowElement).getOutgoingFlows().add(sequenceFlow); 510 } 511 512 //当前分支网关审核不通过到异常结束节点连线 513 sequenceFlow = genarateSequenceFlow("flow3-" + (i + 1) + (j + 1),"不通过", 514 switchGateway.getId(),abnormalEndEvent.getId(),examinationNotPass,process); 515 process.addFlowElement(sequenceFlow); 516 switchGateway.getOutgoingFlows().add(sequenceFlow); 517 518 previousFlowElement = switchGateway; 519 } 520 521 //补充最后一个节点审核通过的分支连线 522 sequenceFlow = genarateSequenceFlow("flow2-" + (i + 1) + (taskNodes.size() + 1),"通过", 523 previousFlowElement.getId(),endEvent.getId(),examinationPass,process); 524 process.addFlowElement(sequenceFlow); 525 ((ExclusiveGateway)previousFlowElement).getOutgoingFlows().add(sequenceFlow); 526 } 527 } 528 return process; 529 } 530 531 /** 532 * Description:节点间连线 533 * Param: 534 * Return: 535 * Auther: cymiao 536 * Date: 2019/9/19 13:53 537 */ 538 protected SequenceFlow genarateSequenceFlow(String id, String name,String sourceRef, String tartgetRef, String conditionExpression, Process process) { 539 SequenceFlow sequenceFlow = new SequenceFlow(sourceRef,tartgetRef); 540 sequenceFlow.setId(id); 541 if(name != null && name != ""){ 542 sequenceFlow.setName(name); 543 } 544 sequenceFlow.setSourceFlowElement(process.getFlowElement(sourceRef)); 545 sequenceFlow.setTargetFlowElement(process.getFlowElement(tartgetRef)); 546 if(conditionExpression !=null && conditionExpression != ""){ 547 sequenceFlow.setConditionExpression(conditionExpression); 548 } 549 return sequenceFlow; 550 } 551 552 /** 553 * Description:创建任务节点 554 * Param: 555 * Return: 556 * Auther: cymiao 557 * Date: 2019/9/19 13:54 558 */ 559 protected UserTask createUserTask(String name,String id,String taskType,String taskTitle){ 560 UserTask task = new UserTask(); 561 task.setName(name); 562 task.setId(id); 563 List<String> candidate = new ArrayList<>(); 564 candidate.add(taskTitle); 565 if("role".equals(taskType)){ 566 task.setCandidateGroups(candidate); 567 }else if("people".equals(taskType)){ 568 task.setCandidateUsers(candidate); 569 } 570 return task; 571 } 572 573 /** 574 * Description:创建条件网关 575 * Param: 576 * Return: 577 * Auther: cymiao 578 * Date: 2019/9/18 19:22 579 */ 580 protected ExclusiveGateway createExclusiveGateway(String name,String id){ 581 ExclusiveGateway exclusiveGateway = new ExclusiveGateway(); 582 exclusiveGateway.setName(name); 583 exclusiveGateway.setId(id); 584 return exclusiveGateway; 585 } 586 587 /** 588 * Description:工作流开始事件 589 * Param: 590 * Return: 591 * Auther: cymiao 592 * Date: 2019/9/18 18:29 593 */ 594 protected StartEvent createStartEvent(){ 595 StartEvent startEvent = new StartEvent(); 596 startEvent.setName("开始"); 597 startEvent.setId("start"); 598 return startEvent; 599 } 600 601 /** 602 * Description:工作流结束事件 603 * Param: 604 * Return: 605 * Auther: cymiao 606 * Date: 2019/9/18 18:30 607 */ 608 protected EndEvent createEndEvent(String id,String name,boolean hasError){ 609 EndEvent endEvent = new EndEvent(); 610 endEvent.setName(name); 611 endEvent.setId(id); 612 if(!hasError){ 613 614 } 615 return endEvent; 616 } 617 }
7)ActivitiExtendOption 审核流流程操作类拓展类
1 @Component 2 @Primary 3 public class ActivitiExtendOption extends ActivitiOption{ 4 5 @Override 6 protected Process createProcess(ProcessEntity processInfo) { 7 Process process = new Process(); 8 9 //ID:org + 组织机构ID + 流程类型 10 process.setId("org" + processInfo.getOrgId() + processInfo.getProcessType()); 11 12 //NAME:组织机构名称 + 流程类型名称 13 process.setName(processInfo.getOrgName() + processInfo.getProcessTypeName()); 14 15 //添加开始事件 16 FlowElement startEvent = createStartEvent(); 17 process.addFlowElement(startEvent); 18 19 //创建异常结束事件 20 FlowElement abnormalEndEvent = createEndEvent("abnormalEnd","异常结束",true); 21 process.addFlowElement(abnormalEndEvent); 22 23 //添加结束事件 24 FlowElement endEvent = createEndEvent("end","结束",false); 25 process.addFlowElement(endEvent); 26 27 List<RuleEntity> rules = processInfo.getRules(); 28 if(null == rules || rules.isEmpty()){ 29 throw new BusinessBaseException(new BusinessExceptionDesc("", BusinessExceptionDesc.SHOW_TYPE.ERROR,"审核流程不能空")); 30 }else{ 31 List<TaskNodeEntity> taskNodes = null; 32 //审核通过和不通过判断表达式 33 String examinationPass = "${examinationStatus == 'pass'}"; 34 String examinationNotPass = "${examinationStatus == 'fail'}"; 35 36 //创建条件网关 37 ExclusiveGateway conditionExclusiveGateway = null; 38 process.addFlowElement(conditionExclusiveGateway = createExclusiveGateway("条件判断网关","condition-gateway")); 39 40 //创建连线:流程开始节点到条件网关的连线 41 SequenceFlow sequenceFlow = genarateSequenceFlow("flow-sc","网关",startEvent.getId(),conditionExclusiveGateway.getId(),"",process); 42 process.addFlowElement(sequenceFlow); 43 44 for (int i = 0; i < rules.size(); i++){ 45 RuleEntity rule = rules.get(i); 46 47 //创建子流程 48 taskNodes = rule.getTaskNodes(); 49 50 //规则重排序 51 Collections.sort(taskNodes, new Comparator<TaskNodeEntity>() { 52 @Override 53 public int compare(TaskNodeEntity o1, TaskNodeEntity o2) { 54 if(o1.getOrder() > o2.getOrder()){ 55 return 1; 56 }else{ 57 return -1; 58 } 59 } 60 }); 61 62 //创建子流程节点选择网关 63 ExclusiveGateway childProcessGatway = createExclusiveGateway("子流程节点选择网关" + rule.getRuleName(),"child-process-gateway" + (i + 1)); 64 process.addFlowElement(childProcessGatway); 65 66 //创建连线:条件网关到子流程节点选择网关的连线 67 String conditionExpression = ""; 68 if("default".equalsIgnoreCase(rule.getRuleType())){ 69 conditionExclusiveGateway.setDefaultFlow("flow-cp" + i); 70 }else if("condition".equalsIgnoreCase(rule.getRuleType())){ 71 conditionExpression = rule.getNumrangeitem().getExpression(); 72 } 73 sequenceFlow = genarateSequenceFlow("flow-cp" + i,rule.getRuleName(), 74 conditionExclusiveGateway.getId(),childProcessGatway.getId(),conditionExpression,process); 75 process.addFlowElement(sequenceFlow); 76 conditionExclusiveGateway.getOutgoingFlows().add(sequenceFlow); 77 78 UserTask userTask = null; 79 TaskNodeEntity previousTaskNodeEntity = null; 80 ExclusiveGateway previousExclusiveGateway = null; 81 for (int j = 0; j < taskNodes.size(); j++){ 82 TaskNodeEntity taskNode = taskNodes.get(j); 83 84 String taskId = taskNode.getNodeType() + taskNode.getNodeTitle() + "-" + rule.getRuleType() + i; 85 86 //创建任务 87 userTask = createUserTask(taskNode.getNodeTitleName(),taskId,taskNode.getNodeType(),taskNode.getNodeTitle()); 88 process.addFlowElement(userTask); 89 90 //创建通过和不通过结果分支网关 91 ExclusiveGateway switchGateway = createExclusiveGateway("结果分支网关","switchGateway" + (i + 1) + (j + 1)); 92 process.addFlowElement(switchGateway); 93 94 //创建当前节点到结果分支网关的连线 95 process.addFlowElement(genarateSequenceFlow("flow-sw" + (i + 1) + (j + 1),"到达分支",taskId,switchGateway.getId(),"",process)); 96 97 /** 98 * 创建连线:节点选择网关到当前任务节点的连线 99 */ 100 conditionExpression = ""; 101 if(previousTaskNodeEntity != null){ 102 StringBuffer expression = new StringBuffer(); 103 expression.append("${"); 104 if(previousTaskNodeEntity.getNodeType().equals("role")){ 105 expression.append("roleCode.contains('"+ previousTaskNodeEntity.getNodeTitle() +"##')"); 106 //expression.append("roleCode == '"+ previousTaskNodeEntity.getNodeTitle() +"'"); 107 }else if(previousTaskNodeEntity.getNodeType().equals("people")){ 108 expression.append("userCode == '"+ previousTaskNodeEntity.getNodeTitle() +"'"); 109 } 110 111 //审核流最后一个节点的所有人发起申请时,自己审核 112 if(j == taskNodes.size() -1){ 113 if(taskNode.getNodeType().equals("role")){ 114 expression.append(" || roleCode.contains( '"+ taskNode.getNodeTitle() +"##')"); 115 }else if(taskNode.getNodeType().equals("people")){ 116 expression.append(" || userCode == '"+ taskNode.getNodeTitle() +"'"); 117 } 118 } 119 expression.append("}"); 120 conditionExpression = expression.toString(); 121 } 122 sequenceFlow = genarateSequenceFlow("flow-pt" + (i + 1) + (j + 1),"节点选择网关到节点",childProcessGatway.getId(),taskId,conditionExpression,process); 123 process.addFlowElement(sequenceFlow); 124 childProcessGatway.getOutgoingFlows().add(sequenceFlow); 125 126 //创建连线:上一个节点到当前节点的连线 127 if(j == 0){ 128 //节点选择网关到第一个任务节点连线,设置为默认选择 129 childProcessGatway.setDefaultFlow("flow-pt" + (i + 1) + (j + 1)); 130 }else if(j > 0){ 131 //上一个任务节点结果分支网关审核通过到当前任务节点连线 132 sequenceFlow = genarateSequenceFlow("flow-swy" +(i + 1) + (j + 1),"通过", 133 previousExclusiveGateway.getId(),taskId,examinationPass,process); 134 process.addFlowElement(sequenceFlow); 135 ((ExclusiveGateway)previousExclusiveGateway).getOutgoingFlows().add(sequenceFlow); 136 } 137 138 //当前分支网关审核不通过到异常结束节点连线 139 sequenceFlow = genarateSequenceFlow("flow-swn" + (i + 1) + (j + 1),"不通过", 140 switchGateway.getId(),abnormalEndEvent.getId(),examinationNotPass,process); 141 process.addFlowElement(sequenceFlow); 142 switchGateway.getOutgoingFlows().add(sequenceFlow); 143 144 //当前结果分支网关设置为上一个结果选择网关 145 previousExclusiveGateway = switchGateway; 146 147 //当前任务节点设置为上一个任务节点 148 previousTaskNodeEntity = taskNode; 149 } 150 151 152 //补充最后一个节点审核通过的分支连线 153 sequenceFlow = genarateSequenceFlow("flow-swy" + (i + 1) + (taskNodes.size() + 1),"通过", 154 previousExclusiveGateway.getId(),endEvent.getId(),examinationPass,process); 155 process.addFlowElement(sequenceFlow); 156 ((ExclusiveGateway)previousExclusiveGateway).getOutgoingFlows().add(sequenceFlow); 157 } 158 } 159 return process; 160 } 161 162 @Override 163 protected void sequenceFlowBackwardAnalysis(FlowElement flowElement, RuleEntity rule, int order) { 164 if(null != flowElement && flowElement instanceof ExclusiveGateway){ 165 ExclusiveGateway switchGateway = (ExclusiveGateway)flowElement; 166 List<SequenceFlow> flows = switchGateway.getOutgoingFlows(); 167 for (SequenceFlow flow : flows){ 168 //下一个任务节点 169 if(flow.getTargetFlowElement() instanceof UserTask){ 170 sequenceFlowBackwardAnalysis(flow.getTargetFlowElement(),rule, ++order); 171 } 172 } 173 }else if(flowElement instanceof UserTask){ 174 UserTask userTask = (UserTask) flowElement; 175 String taskId = userTask.getId(); 176 if(taskId.lastIndexOf("-") > 0){ 177 String suffiz = taskId.substring(taskId.lastIndexOf("-")); 178 taskId = taskId.replace(suffiz,""); 179 } 180 181 //节点类型 182 String nodeType = taskId.contains("people") ? "people" : "role"; 183 184 //节点标题 185 String nodeTitle = taskId.replace(nodeType,""); 186 187 //节点实例 188 TaskNodeEntity nodeEntity = new TaskNodeEntity(nodeType,userTask.getName(),nodeTitle,order); 189 if(!rule.getTaskNodes().contains(nodeEntity)){ 190 rule.getTaskNodes().add(nodeEntity); 191 } 192 193 //下一个节点对象 194 FlowElement nextFlowElement1 = userTask 195 .getOutgoingFlows() 196 .get(0) 197 .getTargetFlowElement(); 198 sequenceFlowBackwardAnalysis(nextFlowElement1,rule, ++order); 199 } 200 //下一个节点是结束事件节点 201 else if(null != flowElement && flowElement instanceof EndEvent){ 202 return; 203 } 204 } 205 } 206 public abstract class BaseBusinessActivitiOption<T extends ApplyDomain> { 207 208 @Autowired 209 protected ActivitiOption activitiOption; 210 211 /** 212 * Description:创建一个申请 213 * Param: 214 * Return: 215 * Auther: cymiao 216 * Date: 2019/9/20 16:36 217 */ 218 public String createApply(T applyInfo, Map<String, Object> variables) { 219 String userOrgId = getCurrentUserOrgId(applyInfo); 220 if(CommonUtils.TextUtil.isEmpty(userOrgId)){ 221 throw new BusinessBaseException(new BusinessExceptionDesc("", BusinessExceptionDesc.SHOW_TYPE.ERROR,"你所属的部门和公司没有配置审核流,请联系管理员!")); 222 } 223 224 //保存申请信息 225 String businessId = saveApplyInfo(applyInfo); 226 227 //开启一个审核流程 228 return activitiOption.startProcessInstance(userOrgId, getCurrentApplyType(), businessId, variables); 229 } 230 231 /** 232 * Description:保存申请信息 233 * Param: 234 * Return: 235 * Auther: cymiao 236 * Date: 2019/9/20 16:37 237 */ 238 protected abstract String saveApplyInfo(T applyInfo); 239 240 /** 241 * Description:获取用户可使用的流程所属的组织结构id 242 * Param: 243 * Return: 244 * Auther: cymiao 245 * Date: 2019/9/20 16:37 246 */ 247 protected abstract String getCurrentUserOrgId(T applyInfo); 248 249 /** 250 * Description:获取用户的申请类型 251 * Param: 252 * Return: 253 * Auther: cymiao 254 * Date: 2019/9/20 16:37 255 */ 256 protected abstract String getCurrentApplyType(); 257 258 protected abstract String getCurrentApplyTypeName(); 259 260 /** 261 * Description:查询用户的待处理审核信息 262 * Param: 263 * Return: 264 * Auther: cymiao 265 * Date: 2019/9/20 16:36 266 */ 267 public List<T> findUserTask(String userCode, String... userRoleCode) { 268 List<T> resultApply = new ArrayList<>(); 269 270 //拥有当前审核类型的组织结构 271 List<String> userOrgIds = getCurrentUserOrgIds(userCode,getCurrentApplyType()); 272 273 //当前用户需要审批的任务 274 List<Task> tasks = new ArrayList<>(); 275 for(String orgId : userOrgIds) { 276 tasks.addAll(activitiOption.findUserTasks( 277 activitiOption.getProcessKey(orgId, getCurrentApplyType()), 278 userCode)); 279 280 } 281 if(null != tasks && !tasks.isEmpty()){ 282 T applyInfo = null; 283 for (Task task : tasks) { 284 String businessKey = activitiOption.findBusinesskeyByProcessInstanceId(task.getProcessInstanceId()); 285 applyInfo = findApplyInfoByBusinessId(getBusinessId(businessKey)); 286 if(null != applyInfo){ 287 applyInfo.setTaskId(task.getId()); 288 resultApply.add(applyInfo); 289 } 290 } 291 } 292 293 //获取当前用户督导的项目 294 List<T> supervisionInfo = findSupervisorApplyInfo(userCode); 295 if(null != supervisionInfo && !supervisionInfo.isEmpty()){ 296 tasks = new ArrayList<>(); 297 tasks.addAll(activitiOption 298 .findRoleTasks( 299 "supervision", 300 0, 301 activitiOption.findRoleTasksCount("supervision"))); 302 303 filterApplyInfo(tasks,supervisionInfo,resultApply); 304 } 305 306 //查询当前用户子用户的申请记录 307 List<T> applyInfos = findUserApplyInfo(userCode); 308 309 if(null != applyInfos && !applyInfos.isEmpty()){ 310 tasks = new ArrayList<>(); 311 for(String orgId : userOrgIds){ 312 if(userRoleCode != null && userRoleCode.length > 0){ 313 //当前用户拥有的角色需要审批的任务 314 for (String roleCode : userRoleCode) { 315 tasks.addAll(activitiOption.findRoleTasks( 316 317 activitiOption.getProcessKey(orgId, getCurrentApplyType()), 318 roleCode)); 319 } 320 } 321 } 322 323 filterApplyInfo(tasks,applyInfos,resultApply); 324 } 325 return resultApply; 326 } 327 328 protected abstract T findApplyInfoByBusinessId(String businessId); 329 330 private void filterApplyInfo(List<Task> tasks,List<T> applyInfos,List<T> resultApply){ 331 if (null != tasks && !tasks.isEmpty()) { 332 String businessKey = null; 333 for (Task task : tasks) { 334 businessKey = activitiOption.findBusinesskeyByProcessInstanceId(task.getProcessInstanceId()); 335 int currentIndex = -1; 336 for (T t : applyInfos) { 337 if (businessKey.equals(getBusinessKey(t))) { 338 t.setTaskId(task.getId()); 339 resultApply.add(t); 340 currentIndex++; 341 break; 342 } 343 } 344 if (currentIndex > -1) { 345 applyInfos.remove(currentIndex); 346 } 347 } 348 } 349 } 350 351 /** 352 * Description:获取当前用户督导的项目信息 353 * Param: 354 * Return: 355 * Auther: cymiao 356 * Date: 2019/10/16 19:48 357 */ 358 protected abstract List<T> findSupervisorApplyInfo(String userCode); 359 360 /** 361 * Description:当前用户可见的拥有当前类型流程的组织机构 362 * Param: 363 * Return: 364 * Auther: cymiao 365 * Date: 2019/9/25 16:07 366 */ 367 protected abstract List<String> getCurrentUserOrgIds(String userCode,String processType); 368 369 /** 370 * Description:申请记录的businessKey 371 * Param: 372 * Return: 373 * Auther: cymiao 374 * Date: 2019/9/20 16:34 375 */ 376 private String getBusinessKey(T t) { 377 Field[] fields = t.getClass().getDeclaredFields(); 378 TableId id; 379 for (Field field : fields) { 380 id = field.getAnnotation(TableId.class); 381 if (id != null) { 382 try { 383 field.setAccessible(true); 384 Object o = field.get(t); 385 return getCurrentApplyType() + "-" + String.valueOf(o); 386 } catch (IllegalAccessException e) { 387 e.printStackTrace(); 388 } 389 } 390 } 391 392 return null; 393 } 394 395 private String getBusinessId(String businessKey){ 396 return businessKey.replaceAll(getCurrentApplyType() + "-",""); 397 } 398 399 /** 400 * Description:用户未完成审核的申请记录 401 * Param: 402 * Return: 403 * Auther: cymiao 404 * Date: 2019/9/20 16:35 405 */ 406 protected abstract List<T> findUserApplyInfo(String userCode); 407 408 /** 409 * Description:发布工作流 410 * Param: 411 * Return: 412 * Auther: cymiao 413 * Date: 2019/9/21 9:58 414 */ 415 public void deploymentProcess(JSONArray propertiyJson) { 416 ProcessEntity processInfo = processPropertyDeal(propertiyJson); 417 activitiOption.deployDeployment(processInfo); 418 } 419 420 /** 421 * Description:发布工作流 422 * Param: 423 * Return: 424 * Auther: cymiao 425 * Date: 2019/9/27 15:06 426 */ 427 public void deploymentProcess(ProcessEntity processInfo){ 428 activitiOption.deployDeployment(processInfo); 429 } 430 431 /** 432 * Description:工作流属性处理 433 * Param: 434 * Return: 435 * Auther: cymiao 436 * Date: 2019/9/21 9:58 437 */ 438 private ProcessEntity processPropertyDeal(JSONArray propertiyJson){ 439 return null; 440 } 441 442 /** 443 * Description:处理申请任务 444 * Param: 445 * Return: 446 * Auther: cymiao 447 * Date: 2019/9/21 16:46 448 */ 449 public String dealApply(String taskId,String examineUser, Map<String,Object> variables){ 450 String processInstanceId = activitiOption.findProcessInstanceIdByTaskId(taskId); 451 String businesskey = activitiOption.findBusinesskeyByProcessInstanceId(processInstanceId); 452 activitiOption.taskComplete(taskId,examineUser,variables); 453 454 String businessId = getBusinessId(businesskey); 455 456 //审核不通过 457 if("fail".equals(String.valueOf(variables.get("examinationStatus")))){ 458 updateBusinessApplyData(businessId,false); 459 }else{ 460 //获取历史 461 List<HistoricActivityInstance> his = activitiOption.findProcessHistoryByStartTime(processInstanceId); 462 if (null != his && !his.isEmpty()){ 463 if("end".equals(his.get(his.size() - 1).getActivityId())){ 464 updateBusinessApplyData(businessId,true); 465 } 466 } 467 } 468 469 return businessId; 470 } 471 472 /** 473 * Description:更新申请记录和业务数据 474 * Param: 475 * Return: 476 * Auther: cymiao 477 * Date: 2019/9/21 17:41 478 */ 479 protected abstract void updateBusinessApplyData(String businessId,boolean examinationStatus); 480 481 /** 482 * Description:获取流程定义 483 * Param: 484 * Return: 485 * Auther: cymiao 486 * Date: 2019/9/26 17:54 487 */ 488 public ProcessEntity findProcess(String orgId){ 489 return activitiOption.findProcess(orgId, getCurrentApplyType(),getCurrentApplyTypeName()); 490 } 491 492 }
8)ActivitiConfig 审核流相关类配置信息
1 @Configuration 2 public class ActivitiConfig { 3 4 @Autowired 5 @Qualifier("dynamicDataSource") 6 private DynamicDataSource dynamicDataSource; 7 8 @Bean 9 public ActivitiEndEventListener endEventListener(){ 10 return new ActivitiEndEventListener(); 11 } 12 13 @Bean 14 public ProcessEngine processEngine(@Autowired ActivitiEndEventListener endEventListener){ 15 StandaloneProcessEngineConfiguration configuration = (StandaloneProcessEngineConfiguration) ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration(); 16 configuration.setDataSource(dynamicDataSource); 17 configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE); 18 19 //添加监听 20 List<ActivitiEventListener> listeners = new ArrayList<>(); 21 listeners.add(endEventListener); 22 configuration.setEventListeners(listeners); 23 24 return configuration.buildProcessEngine(); 25 } 26 27 @Bean 28 public RepositoryService repositoryService(@Autowired ProcessEngine processEngine){ 29 return processEngine.getRepositoryService(); 30 } 31 32 @Bean 33 public RuntimeService runtimeService(@Autowired ProcessEngine processEngine,@Autowired ActivitiEndEventListener endEventListener){ 34 RuntimeService runtimeService = processEngine.getRuntimeService(); 35 endEventListener.setRuntimeService(runtimeService); 36 return runtimeService; 37 } 38 39 @Bean 40 public TaskService taskService(@Autowired ProcessEngine processEngine,@Autowired ActivitiEndEventListener endEventListener){ 41 TaskService taskService = processEngine.getTaskService(); 42 endEventListener.setTaskService(taskService); 43 return taskService; 44 } 45 46 @Bean 47 public HistoryService historyService(@Autowired ProcessEngine processEngine,@Autowired ActivitiEndEventListener endEventListener){ 48 HistoryService historyService = processEngine.getHistoryService(); 49 endEventListener.setHistoryService(historyService); 50 return historyService; 51 } 52 }
4、使用总结
activiti的使用灵活多变,activiti自身有提供配置审核流的界面,经常很难融合与我们自己的产品设计中,所以需要我们按照自己的需求进行二次实现,
当然首当其冲需要解决的问题就是,界面的配置信息应放在怎样的一个载体中,再次就是如何有效的表达审核流的信息使能够生产一个满足业务需求的审核流;
最后就是这些载体信息如何转化为activiti需要的BPMN文件,并且如何反向解析回显配置。
以上这些问题是实现二次开发的最基础也是最重要需要考虑和解决的问题,至于其他的细节就需要在实现的过程中逐步去克服和处理了。