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”)
-
重写服务任务解析器
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)); } } } }
-
重写服务任务行为工厂
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); } }
-
具体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;
}
}
- 注册到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);
}
}