【Activiti】 Activiti工作流引擎 - 提交审批和审批处理示例详解 【精品】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinosoft12345/article/details/84745566

       在上一篇的文章中,我给大家分享了Activiti工作流引擎的API的封装代码,通过我们自己封装的代码,在实际的项目中我们就可以进行工作流相关的开发了。以下内容我们分三个部分:提交审批,审批列表查询,审批处理。

一、提交审批

        提交审批之前,我们需要做好相关的准备工作。在上文中,我提到过:

        1.首先,我们要画工作流程图,并且需要在流程图中设置相关的参数,比如:流程ID、审批人节点,审批条件的判断等,然后我们把生成的.bpmn20.xml放入到我们的项目中,以下展示的是xml里面的内容,主要是看下参数节点的设置。

<process id="activity001" name="活动管理审批流程001" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="分公司市场岗" activiti:assignee="${submitter}"></userTask>
    <userTask id="usertask2" name="分公司总经理" activiti:assignee="${auditNode1}"></userTask>
    <userTask id="usertask3" name="区域市场岗" activiti:assignee="${auditNode2}"></userTask>
    <userTask id="usertask4" name="区域总监" activiti:assignee="${auditNode3}"></userTask>
    <userTask id="usertask5" name="事业部市场岗" activiti:assignee="${auditNode5}"></userTask>
    <userTask id="usertask6" name="品牌管理中心市场岗" activiti:assignee="${auditNode9}"></userTask>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <sequenceFlow id="flow3" name="同意" sourceRef="usertask2" targetRef="usertask3">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approveOpr == '1'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow4" name="同意" sourceRef="usertask3" targetRef="usertask4">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approveOpr == '1'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow5" name="同意" sourceRef="usertask4" targetRef="usertask5">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approveOpr == '1'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow6" name="同意" sourceRef="usertask5" targetRef="usertask6">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approveOpr == '1'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow7" name="同意" sourceRef="usertask6" targetRef="endevent1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approveOpr == '1'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow8" name="不同意" sourceRef="usertask2" targetRef="usertask1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approveOpr == '2'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow9" name="不同意" sourceRef="usertask3" targetRef="usertask1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approveOpr == '2'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow10" name="不同意" sourceRef="usertask4" targetRef="usertask1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approveOpr == '2'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow11" name="不同意" sourceRef="usertask5" targetRef="usertask1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approveOpr == '2'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow12" name="不同意" sourceRef="usertask6" targetRef="usertask1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approveOpr == '2'}]]></conditionExpression>
    </sequenceFlow>
  </process>

2.其次,我们需要根据具体的工作流业务需求选择相应的工作流,主要是需要逻辑判断获取流程ID,这个我们在工作流提交审批的时候会用到。

  public static final String ACTIVITY_AUDIT_PROCESS_DEFINITION_12359 = "workflow001";

  public static final String ACTIVITY_AUDIT_PROCESS_DEFINITION_34579 = "workflow002";

  public static final String ACTIVITY_AUDIT_PROCESS_DEFINITION_6789 = "workflow003";

  public static final String ACTIVITY_AUDIT_PROCESS_DEFINITION_8910 = "workflow004";

  public static final String ACTIVITY_AUDIT_PROCESS_DEFINITION_10 = "workflow005";

3.然后,我们需要把用到的业务参数也需要放入到工作流里面,比如主键ID、查询待审批的业务查询条件。

Map<String, Object> variables = new HashMap<>();
// 活动主题
variables.put(WFVariablesEnum.activityName.name(), record.getActivityName());
// 活动类型
variables.put(WFVariablesEnum.activityType.name(), record.getActivityType());
// 活动组织机构
variables.put(WFVariablesEnum.orgName.name(), record.getOrgName());
// 提报类型
variables.put(WFVariablesEnum.reportType.name(), record.getReportType());
// 提交审批人用户ID
variables.put(WFVariablesEnum.submitter.name(),userId);

好了,现在我们展示一下提交审批的相关代码:

// 1、获取流程定义ID 此处根据前台传的审批人节点来查找工作流
StringBuffer sb = new StringBuffer();
for (TbActivityAuditor tbAuditor : auditorList) {
  sb.append(tbAuditor.getAuditNode());
}
String nodeSqu = sb.toString();
// 2、判断选的工作流是否存在
ProjectApproveEnum pEnum = ProjectApproveEnum.getByStrSeq(nodeSqu);
if (pEnum == null ) {
      resultMap.put("status",false);
      resultMap.put("message","未找到该审批流程的配置,提交审批失败!");
  return resultMap;
}
      String processDefinitonKey = pEnum.getProcessDefinitionKey();
      String businessKey = String.valueOf(record.getId());
      
      Map<String, Object> variables = new HashMap<>();
      // 活动主题
      variables.put(WFVariablesEnum.activityName.name(), record.getActivityName());
      // 活动类型
      variables.put(WFVariablesEnum.activityType.name(), record.getActivityType());
      // 活动组织机构
      variables.put(WFVariablesEnum.orgName.name(), record.getOrgName());
      // 提报类型
      variables.put(WFVariablesEnum.reportType.name(), record.getReportType());
      variables.put(WFVariablesEnum.submitter.name(),userId);
      
      // 设置实体相关所需变量
      for (TbActivityAuditor tbAct : auditorList) {
        if (ReportAuditNodeEnum.getByAuditNode(tbAct.getAuditNode()) != null) {
          ReportAuditNodeEnum  auditorEnum = ReportAuditNodeEnum.getByAuditNode(tbAct.getAuditNode());
          variables.put(auditorEnum.getAuditorVar(), tbAct.getAuditor());
        }
      }

      String processInstanceId = "";
      // 流程发起人设置
      workFlowHandler.setAuthenticatedUserId(String.valueOf(userId));
      ProcessInstance  processInstance = workFlowHandler.startProcessInstanceByKey(processDefinitonKey, businessKey, variables);
      // 
      processInstanceId = processInstance.getId();

然后把获取到的processInstanceId值设置到相应的主键ID对应的数据库表记录上。说到这里,我再提一下数据库表这块的内容,

`process_instance_id` varchar(64) COLLATE utf8_bin DEFAULT '' COMMENT '流程实例ID',

业务表需要添加这个字段,记录工作流流程实例ID,方便我们进行工作流待处理任务的查找。

经过上面的处理,我们已经开启了一个工作流,并且可以进行任务的查找与处理了。 第一部分的内容我们已经完成了。

二、审批列表查询

审批列表查询需要根据我们提交审批部分设置的参数进行查询任务,直接上示例代码:

Map<String, Object> params = new HashMap<String, Object>();

if (StringUtils.isNotBlank(orgName)) {
    params.put(WFVariablesEnum.orgName.toString(), orgName);
}
if (StringUtils.isNotBlank(activityName)) {
    params.put(WFVariablesEnum.activityName.toString(), activityName);
}
if (StringUtils.isNotBlank(activityType) && !"0".equals(activityType)) {
    params.put(WFVariablesEnum.activityType.toString(), Integer.parseInt(activityType));
}

params.put(WFVariablesEnum.reportType1.toString(), new Integer(0));

count = activityReportAuditService.countTaskListByVariables(userId, params);

if (count > 0) {

    page = PageUtils.buildPage(new Page(), (int) count, pageNum, Constant.DefaultPageSize);

    List<Task> tskList = activityReportAuditService.findTaskListByVariables(userId, params, page.getPageStartNumber(), Constant.DefaultPageSize);

    for (Task task : tskList) {    
        String taskId = task.getId();
        String taskName = task.getName();
        String taskAssignee = task.getAssignee();
        String businessKey = workFlowTaskQuery.findBusinessKeyByTaskId(taskId);

        ... ...
    }
}

需要说明一下,首先查询参数的数据类型一定要和提交审批时候的一致,否则查询不出来,其次是需要往工作流传入审批人的用户ID,也就是我们提交审批时候设置的审批人的ID是对应的。  查询列表的时候,我们先去统计记录数,如果记录数为0,我们就不用去查询列表了,减少操作。如果有记录数,那我们就进行分页查询。遍历每一个任务,获取到taskId、taskName、taskAssignee、businessKey,然后去关联业务表的相关数据进行展示。

/**
 * 待审批记录统计
 * @param userId
 * @param vars
 * @return
 * @throws Exception
 */
public long countTaskListByVariables(String userId, Map<String, Object> vars) throws Exception {
  TaskQuery tq = workFlowTaskQuery.createTaskQuery();
  if (vars != null && vars.size() >0) {
    for(Entry<String, Object> entry : vars.entrySet()){
      if (WFVariablesEnum.activityName.toString().equals(entry.getKey()) || 
          WFVariablesEnum.orgName.toString().equals(entry.getKey())) {
        tq.processVariableValueLike(entry.getKey(),"%" +String.valueOf(entry.getValue())+ "%");
      }if (WFVariablesEnum.reportType1.toString().equals(entry.getKey())) {
        tq.processVariableValueLessThanOrEqual(WFVariablesEnum.reportType.toString(), ReportTypeEnum.ACTIVITY_OFFSET.getCode());
      }else {
        tq.processVariableValueEquals(entry.getKey(),entry.getValue());
      }
    }
  }
  
  return workFlowTaskQuery.countTaskAssigneeByTaskQuery(userId, tq);
}

 有些项目的待审批的任务查询条件有些需要特殊处理,比如模糊查询。我们就需要包装一层去处理。

/**
 * 待审批记录列表
 * @param userId
 * @param vars
 * @param start
 * @param limit
 * @return
 * @throws Exception
 */
public List<Task> findTaskListByVariables(String userId, Map<String, Object> vars, int start, int limit)
    throws Exception {
  TaskQuery tq = workFlowTaskQuery.createTaskQuery();
  if (vars != null && vars.size() >0) {
    for(Entry<String, Object> entry : vars.entrySet()){
      if (WFVariablesEnum.activityName.toString().equals(entry.getKey()) || 
          WFVariablesEnum.orgName.toString().equals(entry.getKey())) {
        tq.processVariableValueLike(entry.getKey(), "%" +String.valueOf(entry.getValue())+ "%");
      }if (WFVariablesEnum.reportType1.toString().equals(entry.getKey())) {
        tq.processVariableValueLessThanOrEqual(WFVariablesEnum.reportType.toString(), ReportTypeEnum.ACTIVITY_OFFSET.getCode());
      }else {
        tq.processVariableValueEquals(entry.getKey(),entry.getValue());
      }
    }
  }
  
  return workFlowTaskQuery.taskAssigneeByTaskQuery(userId, tq, start, limit);
}

三、审批处理

审批处理比较复杂,会分很多情况,比如审批通过,审批退回,审批驳回等,那处理方式也是不一样的,我大致说说从控制器controller接收审批处理的开始说起,这里,我只说单笔任务处理的方式,批量的只是要循环处理。

/**
 * 单笔审批
 *
 * @param taskId   任务ID
 * @param auditOpr //审批结果
 * @param comment  审批意见
 * @return
 */
@RequestMapping(value = "/singleAudit", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> singleAudit(@RequestParam(value = "taskId") String taskId,
                                       @RequestParam(value = "auditOpr") String auditOpr,
                                       @RequestParam(value = "comment", required = false) String comment) {
    Map<String, Object> responseMap = new HashMap<String, Object>();
    String userId = String.valueOf(UserAuthorizingUtils.getUserId());


    try {
        if (StringUtils.isBlank(taskId) || StringUtils.isBlank(auditOpr)) {
            throw new ValidationException("参数为空");
        }

        activityReportAuditService.singleAudit(userId, taskId, auditOpr, comment);

        responseMap.put("respCode", RespCodeEnum.R0000.getRespCode());
        responseMap.put("respMsg", RespCodeEnum.R0000.getRespDesc());

    } catch (ValidateException e) {
        logger.info("校验检查", e);

        responseMap.put("respCode", RespCodeEnum.R0001.getRespCode());
        responseMap.put("respMsg", RespCodeEnum.R0001.getRespDesc());

    } catch (Exception e) {
        e.printStackTrace();
        logger.info("系统处理异常", e);

        responseMap.put("respCode", RespCodeEnum.R9999.getRespCode());
        responseMap.put("respMsg", RespCodeEnum.R9999.getRespDesc());
    }


    return responseMap;
}
@Transactional("transactionManager")
@Override
public void singleAudit(String userId, String taskId,String auditOpr,String comment) throws Exception{
  
  try {

    Map<String, Object> variables = new HashMap<String,Object>();

      // 审批通过
      if (AuditOperationEnum.OPER_PASS.getCode().equals(auditOpr)) {
        
        variables.put(WFVariablesEnum.approveOpr.toString(), AuditOperationEnum.OPER_PASS.getCode());
        
        this.auditPass(userId,taskId, variables);
      // 审批退回 
      }else if (AuditOperationEnum.OPER_TOBACK.getCode().equals(auditOpr)) {
        
        variables.put(WFVariablesEnum.approveOpr.toString(), AuditOperationEnum.OPER_TOBACK.getCode());
        
        this.auditBackToInitiator(userId,taskId, comment, variables);
      // 审批驳回 
      }else if (AuditOperationEnum.OPER_REFUSED.getCode().equals(auditOpr)) {
        
        variables.put(WFVariablesEnum.approveOpr.toString(), AuditOperationEnum.OPER_REFUSED.getCode());
        
        this.auditRefuse(userId,taskId, comment, variables);
      }
  } catch (BusinessException e) {
    throw e;
  } catch (Exception e) {
    throw new BusinessException(e);
  }
  
}
@Override
public void auditPass(String userId,String taskId, Map<String, Object> variables) throws Exception {
  try {
    // 1、获取业务主键ID值
    String id = workFlowTaskQuery.findBusinessKeyByTaskId(taskId);
    int recordId = Integer.parseInt(id);
    String taskName = workFlowTaskQuery.taskId(taskId).getName();
    
    // 2、完成工作流任务任务
    workFlowTask.complete(taskId, variables);
    
    // 3、根据recordId查询业务数据
    
    // 4、插入审批记录
    
    // 5、处理暂无负责人
    String processId = record.getProcessInstanceId();
    Task autoTask = null;
    while ( (autoTask = workFlowTaskQuery.processInstanceId(processId)) != null) {
      if (Constant.NO_AUDITOR_CODE.equals(autoTask.getAssignee())) {
        workFlowTask.complete(autoTask.getId(), variables);
      } else {
        break;
      }
    }
    
    ProcessInstance pi = workFlowQuery.processInstanceId(processId);
    // 6、审批流程走完处理逻辑
    if (pi == null) {
      logger.info("-----------------审批流程已走完.--------------",record.getReportNo());

    }else{
      // 7、流程未走完处理逻辑
    }
    
  } catch (Exception e) {
    e.printStackTrace();
    throw new BusinessException("活动立项审批处理异常");
  }
  
}
@Override
public void auditRefuse(String userId,String taskId,String comment, Map<String, Object> variables) throws Exception {
  
  try {
    String id = workFlowTaskQuery.findBusinessKeyByTaskId(taskId);
    int recordId = Integer.parseInt(id);
    String taskName = workFlowTaskQuery.taskId(taskId).getName();
    
    // 1、删除流程实例,结束审批流程
    ProcessInstance pi = workFlowQuery.taskId(taskId);
    String processInstId = pi.getProcessInstanceId();
    workFlow.deleteProcessInstance(processInstId, comment);
    
    // 2、根据recordId更新业务状态
    
    // 3、添加审批记录
    
  } catch (Exception e) {
    e.printStackTrace();
    throw new BusinessException("驳回处理异常");
  }
}
@Override
public void auditBackToInitiator(String userId,String taskId, String comment,Map<String, Object> variables) throws Exception {
  
  try {
    String id = workFlowTaskQuery.findBusinessKeyByTaskId(taskId);
    int recordId = Integer.parseInt(id);
    String taskName = workFlowTaskQuery.taskId(taskId).getName();
    
    // 1、完成任务
    ProcessInstance pi = workFlowQuery.taskId(taskId);
    String processInstId = pi.getProcessInstanceId();
    workFlow.deleteProcessInstance(processInstId, comment);
    
    // 2、根据recordId更新业务数据
    
    
    // 3、添加审批记录

  } catch (Exception e) {
    e.printStackTrace();
    throw new BusinessException("退回处理异常");
  }
}

到现在,我们已经把相关的审批任务的相关内容介绍完了,对需要的朋友应该会有一些帮助, 在当前的技术行业,我们每个人的学习的水平、广度深入都是不一样的,那我们可以把我们所学的东西分享出来,来帮助需要帮助的人。我也希望能够认识更多的朋友,我们一起进步。

猜你喜欢

转载自blog.csdn.net/sinosoft12345/article/details/84745566