flowable工作流定制化修改

本文介绍了如何对Flowable工作流进行定制化修改,包括自定义Id生成器、用户任务拦截器、流程规则校验器,以及扩展服务任务,如定义`flowable:type="rest"`的服务任务,并提供了相关代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Id生成器自定义

实现org.flowable.common.engine.impl.cfg.IdGenerator

public class SnowFlakeIdGenerator implements IdGenerator {
    @Override
    public String getNextId() {
        return SnowflakeId.nextStr();
    }
}

ProcessEngine中配置IdGenerator

@Bean(destroyMethod = "close")
public ProcessEngine configure(SpringProcessEngineConfiguration engineConfiguration) {
    engineConfiguration.setIdGenerator(new SnowFlakeIdGenerator());
    return engineConfiguration.buildProcessEngine();
}

自定义用户任务拦截器

自定义用户任务拦截器org.flowable.engine.interceptor.CreateUserTaskInterceptor
比如有关若依Flowable相关的代码需要填充任务的category属性,咱们这边就可以使用用户任务的拦截器给用户任务添加category属性

@Slf4j
public class CustomCreateUserTaskInterceptor implements CreateUserTaskInterceptor {
    @Override
    public void beforeCreateUserTask(CreateUserTaskBeforeContext context) {
        ProcessDefinitionEntity processDefinitionEntity = CommandContextUtil.getProcessDefinitionEntityManager()
            .findById(context.getExecution().getProcessDefinitionId());
        DeploymentEntity deploymentEntity =
            CommandContextUtil.getDeploymentEntityManager().findById(processDefinitionEntity.getDeploymentId());
        context.setCategory(deploymentEntity.getCategory());
    }
    @Override
    public void afterCreateUserTask(CreateUserTaskAfterContext context) {
        // do something
    }
}

在这里插入图片描述在这里插入图片描述

@Bean(destroyMethod = "close")
public ProcessEngine configure(SpringProcessEngineConfiguration engineConfiguration) {
    engineConfiguration.setCreateUserTaskInterceptor(new CustomCreateUserTaskInterceptor());
    return engineConfiguration.buildProcessEngine();
}

源码中org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior

public class UserTaskActivityBehavior extends TaskActivityBehavior implements ActivityWithMigrationContextBehavior {
 ...
    @Override
    public void execute(DelegateExecution execution, MigrationContext migrationContext) {
       ......
        
        if (processEngineConfiguration.getCreateUserTaskInterceptor() != null) {
            processEngineConfiguration.getCreateUserTaskInterceptor().beforeCreateUserTask(beforeContext);
        }

       ......

        
            if (processEngineConfiguration.getCreateUserTaskInterceptor() != null) {
                CreateUserTaskAfterContext afterContext = new CreateUserTaskAfterContext(userTask, task, execution);
                processEngineConfiguration.getCreateUserTaskInterceptor().afterCreateUserTask(afterContext);
            }
            ......

    }

}

自定义流程规则校验器

@Bean(destroyMethod = "close")
public ProcessEngine configure(SpringProcessEngineConfiguration engineConfiguration) {
    engineConfiguration.setProcessValidator(createProcessValidator());
    return engineConfiguration.buildProcessEngine();
}
private ProcessValidator createProcessValidator() {
    ProcessValidatorImpl processValidatorImpl = new ProcessValidatorImpl();
    ValidatorSet flowableExecutableProcessValidatorSet =
        new ValidatorSetFactory().createFlowableExecutableProcessValidatorSet();
    // 这边去定制化各种验证校验器
    flowableExecutableProcessValidatorSet.addValidator(new CustomBpmnValidator());
    processValidatorImpl.addValidatorSet(flowableExecutableProcessValidatorSet);
    return processValidatorImpl;
}

简单检查流程是否存在开始、结束节点

public class CustomBpmnValidator extends ValidatorImpl {
    @Override
    public void validate(BpmnModel bpmnModel, List<ValidationError> errors) {
        Process mainProcess = bpmnModel.getMainProcess();
        List<UserTask> userTasks = mainProcess.findFlowElementsOfType(UserTask.class);
        List<StartEvent> startEvents = mainProcess.findFlowElementsOfType(StartEvent.class);
        List<EndEvent> endEvents = mainProcess.findFlowElementsOfType(EndEvent.class);
        if (CollectionUtils.isEmpty(startEvents) || CollectionUtils.isEmpty(endEvents)) {
            addError(errors, "流程必须存在开始或结束节点", mainProcess, "流程必须存在开始或结束节点");
        }
    }
}

扩展服务任务(定义flowable:type=“rest”)

  1. 重写服务任务解析器

    public class CustomServiceTaskParseHandler extends ServiceTaskParseHandler {
    
        @Override
        protected void executeParse(BpmnParse bpmnParse, ServiceTask serviceTask) {
            super.executeParse(bpmnParse, serviceTask);
            if (StringUtils.isNotBlank(serviceTask.getType())) {
                if (StringUtils.equalsIgnoreCase(ServiceTaskTypeEnum.REST.getType(), serviceTask.getType())) {
                    serviceTask.setBehavior(((CustomActivityBehaviorFactory)bpmnParse.getActivityBehaviorFactory())
                        .createHttpActivityBehavior(serviceTask));
                }
            }
        }
    }
    
  2. 重写服务任务行为工厂

    public class CustomActivityBehaviorFactory extends DefaultActivityBehaviorFactory {
        @Override
        public RestCallTaskActivityBehavior createHttpActivityBehavior(ServiceTask serviceTask) {
            List<FieldDeclaration> fieldDeclarations = super.createFieldDeclarations(serviceTask.getFieldExtensions());
            return (RestCallTaskActivityBehavior)ClassDelegate
                .defaultInstantiateDelegate(RestCallTaskActivityBehavior.class, fieldDeclarations);
        }
    }
    
  3. 具体ServiceTask业务实现

@Slf4j
@SuppressWarnings("all")
public class RestCallTaskActivityBehavior extends AbstractBpmnActivityBehavior {
  private static final long serialVersionUID = 3398161161525709990L;
  /**
   * 请求方法 POST GET
   */
  private Expression requestMethod;
  /**
   * 请求URL
   */
  private Expression requestUrl;
  /**
   * 交易编码
   */
  private Expression transCode;
  /**
   * 服务接收方
   */
  private Expression recvApp;
  /**
   * 请求体
   */
  private Expression requestBody;

  private Expression saveResponseParameters;
  /**
   * 返回变量名
   */
  private Expression responseVariableName;

  @Override
  public void execute(DelegateExecution execution) {
      // 获取各属性的值 这5个属性都在校验器中做了参数检查
      String requestMethodStr = getStringFromField(requestMethod, execution);
      String requestUrlStr = getStringFromField(requestUrl, execution);
      String transCodeStr = getStringFromField(transCode, execution);
      String recvAppStr = getStringFromField(recvApp, execution);
      String requestBodyStr = getStringFromField(requestBody, execution);
      String saveResponseParametersStr = getStringFromField(saveResponseParameters, execution);
      // 执行restful
      executeRestfulRequest(execution, requestUrlStr, requestMethodStr, recvAppStr, transCodeStr, requestBodyStr,
          saveResponseParametersStr);
      // 离开当前节点
      leave(execution);
  }

  /**
   * @param execution
   * @param requestUrl 请求url
   * @param requestMethodStr 请求方法
   * @param recvAppStr 接收方
   * @param transCodeStr 交易编码
   * @param requestBodyStr 请求体
   * @param saveResponseParametersStr 是否保存响应结果到流程变量中
   */
  private void executeRestfulRequest(DelegateExecution execution, String requestUrl, String requestMethodStr,
      String recvAppStr, String transCodeStr, String requestBodyStr, String saveResponseParametersStr) {
      try {
          // 从Spring容器获取RestTemplate
          RestTemplate restTemplate = SpringUtil.getBeanByType(RestTemplate.class);
          // 组装请求Header 默认都是application/json请求与接收
          HttpHeaders restHeaders = new HttpHeaders();
          restHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
          restHeaders.setContentType(MediaType.APPLICATION_JSON);

          // 组装请求体
          Map<String, Object> requestBody = new HashMap<>();
          Map<String, Object> params = JSONObject.parseObject(requestBodyStr, Map.class);
          if (MapUtils.isNotEmpty(params)) {
              for (Map.Entry<String, Object> entry : params.entrySet()) {
                  String paramKey = entry.getKey();
                  Object paramValue = entry.getValue();
                  Matcher matcher = VARIABLE_REGEX.matcher(Convert.toStr(paramValue));
                  if (matcher.find()) {
                      // 匹配后,从流程变量中获取参数
                      params.put(paramKey, execution.getVariable(Convert.toStr(matcher.group(1))));
                  } else {
                      // 不匹配,认为就是xml配置的内容
                      params.put(paramKey, paramValue);
                  }
              }
          }

          // 执行请求调用
          ResponseEntity<String> result =
              restTemplate.exchange(requestUrl, RequestMethodEnum.of(requestMethodStr), httpEntity, String.class);
          if (StringUtils.equalsIgnoreCase(saveResponseParametersStr,"true")) {
              // 提取结果内容
              String response = result.getBody();
              String responseVariableNameStr = getStringFromField(responseVariableName, execution);
              Map<String, String> responseParams = JSONObject.parseObject(responseVariableNameStr, Map.class);
              if (StringUtils.isNotBlank(response) && MapUtils.isNotEmpty(responseParams)) {
                  Map<String, Object> variables = Maps.newHashMap();
                  for (Map.Entry<String, String> entry : responseParams.entrySet()) {
                      // 解析异常抛出异常
                      variables.put(entry.getKey(), JsonPathUtils.getValue(response, entry.getValue()));
                  }
                  if (MapUtils.isNotEmpty(variables)) {
                      // 设置流程变量
                      execution.setVariables(variables);
                  }
              }
          }

      } catch (Exception e) {
          log.error("ServiceTask Rest request error", e);
          // 异常就不设置值 走默认流转
      } finally {
          // TODO 可以记录服务任务的操作记录
      }
  }

  private static String getStringFromField(Expression expression, DelegateExecution execution) {
      if (Objects.nonNull(expression)) {
          Object value = expression.getValue(execution);
          if (Objects.nonNull(value)) {
              return Convert.toStr(value);
          }
      }
      return null;
  }

}
  1. 注册到Spring容器
@Bean(destroyMethod = "close")
public ProcessEngine configure(SpringProcessEngineConfiguration engineConfiguration) {
    // 设置自定义服务任务解析器
    engineConfiguration
        .setCustomDefaultBpmnParseHandlers(Collections.singletonList(new CustomServiceTaskParseHandler()));
    // 设置自定义活动行为工厂 重写服务任务ServiceTask
    engineConfiguration.setActivityBehaviorFactory(new CustomActivityBehaviorFactory());
    return engineConfiguration.buildProcessEngine();
}

自定义属性flowable:xxx=""

目前flowable 6.8.0针对所有FlowElement自定义业务属性和扩展属性
6.8.0之前部分流程元素节点不支持自定义属性以及扩展属性
举个例子

    <process id="test">
        <startEvent id="start" flowable:test="test"/>
        <sequenceFlow sourceRef="start" targetRef="parallelSplit"/>
        .......
        <endEvent id="end"/>
    </process>
public class StartEventXMLConverter extends BaseBpmnXMLConverter {
    
    protected Map<String, BaseChildElementParser> childParserMap = new HashMap<>();
    
    protected static final List<ExtensionAttribute> defaultStartEventAttributes = Arrays.asList(
            new ExtensionAttribute(ATTRIBUTE_FORM_FORMKEY),
            new ExtensionAttribute(ATTRIBUTE_FORM_FIELD_VALIDATION),
            new ExtensionAttribute(ATTRIBUTE_EVENT_START_INITIATOR),
            new ExtensionAttribute(ATTRIBUTE_EVENT_START_INTERRUPTING),
            new ExtensionAttribute(ATTRIBUTE_SAME_DEPLOYMENT));
    
    public StartEventXMLConverter() {
        VariableListenerEventDefinitionParser variableListenerEventDefinitionParser = new VariableListenerEventDefinitionParser();
        childParserMap.put(variableListenerEventDefinitionParser.getElementName(), variableListenerEventDefinitionParser);
    }

    @Override
    public Class<? extends BaseElement> getBpmnElementType() {
        return StartEvent.class;
    }

    @Override
    protected String getXMLElementName() {
        return ELEMENT_EVENT_START;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected BaseElement convertXMLToElement(XMLStreamReader xtr, BpmnModel model) throws Exception {
        String formKey = BpmnXMLUtil.getAttributeValue(ATTRIBUTE_FORM_FORMKEY, xtr);
        StartEvent startEvent = null;
        if (StringUtils.isNotEmpty(formKey)) {
            if (model.getStartEventFormTypes() != null && model.getStartEventFormTypes().contains(formKey)) {
                startEvent = new AlfrescoStartEvent();
            }
        }
        if (startEvent == null) {
            startEvent = new StartEvent();
        }

        BpmnXMLUtil.addXMLLocation(startEvent, xtr);
        String elementId = xtr.getAttributeValue(null, ATTRIBUTE_ID);
        startEvent.setId(elementId);
        
        startEvent.setInitiator(BpmnXMLUtil.getAttributeValue(ATTRIBUTE_EVENT_START_INITIATOR, xtr));
        boolean interrupting = true;
        String interruptingAttribute = xtr.getAttributeValue(null, ATTRIBUTE_EVENT_START_INTERRUPTING);
        if (ATTRIBUTE_VALUE_FALSE.equalsIgnoreCase(interruptingAttribute)) {
            interrupting = false;
        }

        startEvent.setInterrupting(interrupting);
        startEvent.setFormKey(formKey);
        String formValidation = BpmnXMLUtil.getAttributeValue(BpmnXMLConstants.ATTRIBUTE_FORM_FIELD_VALIDATION, xtr);
        startEvent.setValidateFormFields(formValidation);

        String sameDeploymentAttribute = BpmnXMLUtil.getAttributeValue(ATTRIBUTE_SAME_DEPLOYMENT, xtr);
        if (ATTRIBUTE_VALUE_FALSE.equalsIgnoreCase(sameDeploymentAttribute)) {
            startEvent.setSameDeployment(false);
        }
        // 老版本没有的方法 具体可以看下6.8.0之前的版本 如6.7.2版本
        BpmnXMLUtil.addCustomAttributes(xtr, startEvent, defaultElementAttributes, defaultActivityAttributes, defaultStartEventAttributes);

        parseChildElements(getXMLElementName(), startEvent, childParserMap, model, xtr);

        return startEvent;
    }

    @Override
    protected void writeAdditionalAttributes(BaseElement element, BpmnModel model, XMLStreamWriter xtw) throws Exception {
        StartEvent startEvent = (StartEvent) element;
        writeQualifiedAttribute(ATTRIBUTE_EVENT_START_INITIATOR, startEvent.getInitiator(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_FORM_FORMKEY, startEvent.getFormKey(), xtw);
        writeQualifiedAttribute(ATTRIBUTE_FORM_FIELD_VALIDATION, startEvent.getValidateFormFields(), xtw);

        if (!startEvent.isSameDeployment()) {
            // default value is true
            writeQualifiedAttribute(ATTRIBUTE_SAME_DEPLOYMENT, "false", xtw);
        }

        if ((startEvent.getEventDefinitions() != null && startEvent.getEventDefinitions().size() > 0) ||
                (startEvent.getExtensionElements() != null && startEvent.getExtensionElements().containsKey(ELEMENT_EVENT_TYPE))) {
            writeDefaultAttribute(ATTRIBUTE_EVENT_START_INTERRUPTING, String.valueOf(startEvent.isInterrupting()), xtw);
        }
    }

    @Override
    protected boolean writeExtensionChildElements(BaseElement element, boolean didWriteExtensionStartElement, XMLStreamWriter xtw) throws Exception {
        StartEvent startEvent = (StartEvent) element;
        didWriteExtensionStartElement = writeVariableListenerDefinition(startEvent, didWriteExtensionStartElement, xtw);
        didWriteExtensionStartElement = writeFormProperties(startEvent, didWriteExtensionStartElement, xtw);
        return didWriteExtensionStartElement;
    }

    @Override
    protected void writeAdditionalChildElements(BaseElement element, BpmnModel model, XMLStreamWriter xtw) throws Exception {
        StartEvent startEvent = (StartEvent) element;
        writeEventDefinitions(startEvent, startEvent.getEventDefinitions(), model, xtw);
    }
}

其他自定义后续补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游侠小马哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值