节点前后置事件脚本

概况

  1. 事件脚本是针对流程任务创建或完成的处理逻辑进行增强,如普通任务创建、会签任务创建、任务完成等动作的逻辑增强;

  2. 前置事件脚本,即在普通任务创建、会签任务创建逻辑后执行,代码切入点com.ak.iform.bpmn.activiti.ext.listener.task.AbstractTaskListener.exeEventScript(BpmDelegateTask)

  3. 后置事件脚本,即在任务完成动作逻辑后执行,代码切入点com.ak.iform.bpmn.activiti.ext.listener.task.AbstractTaskListener.exeEventScript(BpmDelegateTask)

  4. 脚本内容是groovy脚本,如:

     import java.util.HashMap;
     import java.util.Map;
    
     Map<String, String> params = new HashMap<>();
     params.put("ming_cheng_", "id_");
     params.put("shu_liang_", "ku_cun_");
     businessScript.syncNumberDataBySql(businessKey_, "t_enterdetail", "parent_id_", "ming_cheng_", "t_consumablesbasic", "id_", params, true);

操作说明

在【工作流程】-【流程定义管理】选择某条数据,点击“设置”按钮,进入流程设置页面,然后在左边选中“用户任务”图标的节点,然后在右边出现的“事件设置”选择“编写脚本”,编写以下代码范例即可,如:

    import java.util.HashMap;
    import java.util.Map;

    Map<String, String> params = new HashMap<>();
    params.put("ming_cheng_", "id_");
    params.put("shu_liang_", "ku_cun_");
    businessScript.syncNumberDataBySql(businessKey_, "t_enterdetail", "parent_id_", "ming_cheng_", "t_consumablesbasic", "id_", params, true);

脚本常用逻辑示例

脚本语言是Groovy,它可以理解为java的一个动态方法,我们只需要编写方法体内容即可
它可以调用到任何注入到spring容器中的bean,写对beanId就可以
语法就是java语法,我们在一个java方法内怎么写代码这里就这么写
里面内置的可用对象:

  1. cmd,流程命令对象,可以获取业务数据、跳转节点
  2. [业务对象编码],业务对象实体,可以获取或修改业务字段值
  3. 其他注入到Spring容器的Bean,如:cscript,通用脚本、bpmnScript,流程相关脚本、businessScript,业务相关脚本、jdbcScript,数据库操作相关脚本等

常用Bean列表

BeanID Bean说明 使用文档
cmd IFORM流程执行对象(任务、实例) 在这里
execution Activiti任务执行对象 在这里
mybatisTemplateProvider SQL执行对象(基于Mybatis,事务一致) 在这里
jdbcScript SQL脚本对象(基于JdbcTemplate,事务不一致) 在这里
bpmnScript 流程脚本对象 在这里
businessScript 业务脚本对象 在这里
cscript 通用脚本对象 在这里
thridServiceScript 第三方服务脚本对象 在这里
validationScript 校验脚本对象 在这里

说明:功能操作使用说明,移步地址:[Groovy脚本使用说明]

如何获取业务数据

  1. 如何获取业务数据
    String busData = cmd.getBusData();
    //或者直接使用业务对象编码调用getData()方法获取
    // [业务对象编码].get("字段名")
  2. 业务数据需要调用时设置到请求参数中,如果是外部url表单方式需要按照前端编写getFormData方法给接口返回表单数据;

如何获取动作类型

  1. 获取方式
     // 枚举详见com.ak.iform.bpmn.api.constant.NodeStatus
     String actionName = cmd.getActionName();
  2. 使用示例,根据动作类型确定如何修改业务数据
     import com.ak.iform.bpmn.api.constant.NodeStatus;
     String actionName = cmd.getActionName();
     if(NodeStatus.AGREE.getKey().equals(actionName)) {
         // 执行同意动作该执行什么逻辑
         // 如:将业务数据中的状态改为“审批中”
     }
     else if(NodeStatus.OPPOSE.getKey().equals(actionName)) {
         // 执行反对动作该执行什么逻辑
         // 如:将业务数据中的状态改为“审批不通过”
     }

如何获取界面或接口传入下一个节点ID

最终体现都是接口参数传入,详情请查阅:

  1. 获取接口指定的节点

    String destination = cmd.getDestination();
  2. 使用示例,根据节点确定如何修改业务数据

     String destination = cmd.getDestination();
     if("End_Event_ssgu7".equals(destination)) {
         // 跳转到结束节点该执行什么逻辑
         // 如:将业务数据中的状态改为“审批不通过”
     }
     else if("Activiti_jfsjh&&^".equals(destination)) {
         // 跳转到下一个审批节点该执行什么逻辑
         // 如:将业务数据中的状态改为“审批中”
     }

获取当前节点审批人

仅在节点前置事件可用

        import java.util.ArrayList;
        import java.util.Collections;
        import java.util.List;
        import com.ak.iform.base.core.util.BeanUtils;
        import com.ak.iform.bpmn.api.constant.BpmConstants;
        import com.ak.iform.bpmn.api.model.delegate.BpmDelegateTask;
        import com.ak.iform.bpmn.api.model.identity.BpmIdentity;

        List<BpmIdentity> executors = execution.getExecutors();
        if (BeanUtils.isEmpty(executors)) {
            executors = cmd.getBpmIdentities().get(execution.getTaskDefinitionKey());
        }

        if (BeanUtils.isNotEmpty(executors)) {
            return executors;
        }

        BpmIdentity taskExecutor = (BpmIdentity) execution.getVariable(BpmConstants.ASIGNEE);
        if (BeanUtils.isEmpty(taskExecutor)) {
            return Collections.emptyList();
        }

        executors = new ArrayList<BpmIdentity>();
        executors.add(taskExecutor);

获取流程图下一个节点(v3.5.1以下)

仅在后置事件可用
下一个节点是结束节点的后置事件不可用

        import java.util.Optional;
        import com.ak.iform.bpmn.persistence.entity.BpmInstPo;
        import java.util.List;
        import com.ak.iform.bpmn.api.model.node.IBpmNodeDefine;
        import com.ak.iform.bpmn.api.service.BpmIdentityService;
        import com.ak.iform.base.core.util.AppUtil;
        import com.ak.iform.bpmn.api.identity.BpmIdentityExtractService;
        import com.ak.iform.bpmn.api.constant.BpmConstants;
        import java.util.Map;

        Object processInstObject = cmd.getVariable(BpmConstants.PROCESS_INST);
        processInstObject =
            Optional.ofNullable(processInstObject).orElse(cmd.getTransitVars(BpmConstants.PROCESS_INST));
        BpmInstPo bpmInstPo = (BpmInstPo)processInstObject;
        if (bpmInstPo != null) {            
            List<IBpmNodeDefine> outcomeNodes = nodeDef.getOutgoingNodeList();
            BpmIdentityService bpmIdentityService = AppUtil.getBean(BpmIdentityService.class);
            BpmIdentityExtractService bpmIdentityExtractService = AppUtil.getBean(BpmIdentityExtractService.class);
            Map<String, Object> variables = bpmIdentityService.createVariableMap(bpmInstPo.getId());
            String startId = (String)variables.get(BpmConstants.START_USER);
            for (IBpmNodeDefine nodeDefItem : outcomeNodes) {
                List<BpmIdentity> userList = bpmIdentityService.findByDefIdNodeIdData(startId,
                    bpmInstPo.getProcDefId(), bpmInstPo.getId(), nodeDefItem.getNodeId(), true, true);
                List<Map<String, String>> userMapList = bpmIdentityExtractService.extractUser(userList);// TODO 每个节点的用户
            }
        }

获取流程图下一个节点(v3.5.1以上(含))

仅在后置事件可用
下一个节点是结束节点的后置事件不可用

        import java.util.Optional;
        import com.ak.iform.bpmn.persistence.entity.BpmInstPo;
        import java.util.List;
        import com.ak.iform.bpmn.api.model.node.IBpmNodeDefine;
        import com.ak.iform.bpmn.api.service.BpmIdentityService;
        import com.ak.iform.base.core.util.AppUtil;
        import com.ak.iform.bpmn.api.identity.BpmIdentityExtractService;
        import com.ak.iform.bpmn.api.constant.BpmConstants;
        import java.util.Map;

        Object processInstObject = cmd.getVariable(BpmConstants.PROCESS_INST);
        processInstObject =
            Optional.ofNullable(processInstObject).orElse(cmd.getTransitVars(BpmConstants.PROCESS_INST));
        BpmInstPo bpmInstPo = (BpmInstPo)processInstObject;
        if (bpmInstPo != null) {
            List<IBpmNodeDefine> outcomeNodes = nodeDef.getOutgoingNodeList();
            BpmIdentityService bpmIdentityService = AppUtil.getBean(BpmIdentityService.class);
            BpmIdentityExtractService bpmIdentityExtractService = AppUtil.getBean(BpmIdentityExtractService.class);
            Map<String, Object> variables = bpmIdentityService.createVariableMap(bpmInstPo.getId());
            String startId = (String)variables.get(BpmConstants.START_USER);
            for (IBpmNodeDefine nodeDefItem : outcomeNodes) {
                List<BpmIdentity> userList = bpmIdentityService.findByDefIdNodeIdData(variables, startId,
                    bpmInstPo.getProcDefId(), bpmInstPo.getId(), nodeDefItem.getNodeId(), true, true);
                List<Map<String, String>> userMapList = bpmIdentityExtractService.extractUser(userList);// TODO 每个节点的用户
            }
        }

通过httpclient请求接口

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

String taskId = execution.getId(); // 任务id
String busData = cmd.getBusData(); // 表单数据json
String bussnessKey = cmd.getBusinessKey(); // 表单数据,也就是业务数据的主键

String url = "http://192.168.3.230:15100/iform/business/v3/form/def/query";
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("aa", "bb");
StringEntity s = new StringEntity("{\"parameters\":[],\"requestPage\":{\"limit\":20,\"needPage\":true,\"pageNo\":1},\"sorts\":[]}");
s.setContentEncoding("UTF-8");
s.setContentType("application/json");//发送json数据需要设置contentType
httpPost.setEntity(s);
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
// TODO 处理返回逻辑
EntityUtils.consume(entity);

注:
如果在脚本里面使用jdbcScript修改了数据需要手动调用缓存清除方法清除缓存com.ak.iform.base.framework.utils.J2CacheUtil.flushAll()。多个脚本修改数据,只需在最后一个脚本写上清除缓存脚本即可。
如果当前节点执行后会跳过下一个节点需要同步修改线程上下文中的数据对象数据[业务对象编码].set("字段名",值)

作者:黄春艳  创建时间:2024-12-11 11:49
最后编辑:黄春艳  更新时间:2025-02-14 10:41