暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Flowable 实现扩展UserTask自定义属性

ITSK 2021-03-28
10217
上篇文章介绍了针对流程定义属性的扩展,这篇文章介绍针对UserTask用户任务元素的属性扩展。
流程图模板bpmn xml文件中flowable规范【xmlns:flowable】针对UserTask用户任务元素提供了基本属性及可扩展属性如下所示:
<definitions 
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:flowable="http://flowable.org/bpmn"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<!-- id:流程定义key name:流程定义名称 isExecutable:是否可执行-->
<!-- flowable:自定义属性名="自定义属性值" -->
<process id="test_bpmn" name="test BPMN" isExecutable="true"
flowable:organizationCode="流程所属组织编码" >
... ...
     <userTask id="test_usertask" name="用户任务测试" 
      flowable:assignee="张三" flowable:owner="李四" 
      flowable:formKey="表单地址" 
      flowable:customArr="自定义属性">
          <!-- 监听器配置  -->
          <extensionElements>
           <!-- class类型 -->
             <flowable:taskListener event="complete" class="com.flow.test.flowabledemo.service.MyListener.MyTaskListener"/>
             <!-- 表达式类型 -->
<flowable:taskListener expression="${myExpressionExecutionListener.test(execution.eventName)}" event="complete" />
              <!-- 脚本类型类型 -->
               <flowable:taskListener event="complete" class="org.flowable.engine.impl.bpmn.listener.ScriptTaskListener" >
<flowable:field name="script">
<flowable:string>
def bar = "BAR"; // local variable
foo = "FOO"; // pushes variable to execution context
task.setOwner("kermit"); // test access to task instance
bar // implicit return value
</flowable:string>
</flowable:field>
<flowable:field name="language" stringValue="groovy" />
<flowable:field name="resultVariable" stringValue="myVar" />
</flowable:taskListener>
      </extensionElements>
</userTask>
... ...
</process>
... ...


</definitions>

调用BpmnXMLConverter convertToBpmnModel()方法可以实现将bpmn xml转换成BpmnModel内存模型对象,然后将flowable:customArr="自定义属性"映射到UserTask对象的attributes属性中,debug如下图所示:

我们可以看到flowable使用BpmnXMLConverter的convertToBpmnModel()方法可以将读取的bpmn xml文件中的扩展属性转到对应的UserTask类定义的扩展属性:Map<String, List<ExtensionAttribute>> attributes中,大家看下源码就知道了,这里不详细粘贴了。嗯哼太乐观了,将该流程图模板保存以后部署之前是插入到act_de_model表【流程模型信息表】,仅用于保存流程模板bpmn信息,只有在流程部署以后生成流程定义信息才能被流程引擎使用。

我们看到act_de_model表并没有存在bpmn xml文件而是转换成json格式进行存储的,代码实现如下:


/**
* bpmn xml和BpmnModel 转换器
*/
private BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
/**
* bpmn json和BpmnModel 转换器
*/
private BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();


XMLStreamReader reader = null;
InputStream inputStream = null;
try {
XMLInputFactory factory = XMLInputFactory.newInstance();
inputStream = new FileInputStream(new File(filePath));
reader = factory.createXMLStreamReader(inputStream);
//校验bpmn xml文件是否异常
BpmnModel bpmnModel = bpmnXMLConverter.convertToBpmnModel(reader);
List<Process> processes = bpmnModel.getProcesses();
if (CollectionUtils.isEmpty(processes)) {
log.error("BPMN模型没有配置流程");
return null;
}


/**
* 获取流程定义信息
*/
Process mainProcess = bpmnModel.getMainProcess();
//获取流程定义信息
//获取流程key
String id = mainProcess.getId();
//获取流程名称
String name = mainProcess.getName();
//获取流程描述
String documentation = mainProcess.getDocumentation();
//获取process节点中的扩展属性信息
Map<String, List<ExtensionAttribute>> attributes = mainProcess.getAttributes();
for (Map.Entry<String, List<ExtensionAttribute>> entry : attributes.entrySet()) {
System.out.println("扩展属性key:" + entry.getKey() + ",对应的值:" + entry.getValue().get(0).getValue());
}

//保存或修改的流程模板信息
Model newModel = new Model();
// 查询是否已经存在流程模板 :即判断是修改还是新增
List<Model> existModelList = modelRepository.findByKeyAndType(mainProcess.getId(), AbstractModel.MODEL_TYPE_BPMN);
if (!existModelList.isEmpty()) {
newModel.setId(existModelList.get(0).getId());
}
User userDo = new FlowUser();
userDo.setId("aaaaaaaa");
//设置流程名称
newModel.setName(mainProcess.getName());
//设置流程编码
newModel.setKey(mainProcess.getId());
//设置流程引擎类型
newModel.setModelType(AbstractModel.MODEL_TYPE_BPMN);
// newModel.setCreated(DateUtils.getCurrentTime());
//设置流程描述
newModel.setDescription(mainProcess.getDocumentation());
//设置模板json格式
ObjectNode bpmnJson = bpmnJsonConverter.convertToJson(bpmnModel);
newModel.setModelEditorJson(bpmnJson.toString());
if (StringUtils.isEmpty(newModel.getId())) {
//修改
newModel.setLastUpdated(Calendar.getInstance().getTime());
newModel.setLastUpdatedBy(userDo.getId());
} else {
//新增
newModel.setCreated(Calendar.getInstance().getTime());
newModel.setCreatedBy(userDo.getId());
}
modelService.createModel(newModel, userDo);
} catch (Exception e) {
log.error("BPMN模型创建流程异常", e);
return null;
} finally {
try {
reader.close();
} catch (XMLStreamException e) {
log.error("关闭异常", e);
}
}
}

我们看下flowable是如何实现UserTask元素的BpmnModel和bpmn Json转换的,如何是debug的一步步流程:

那么UserTaskJsonConverter是什么时候被加载的?我们看BpmnJsonConverter部分源码如下:

public class BpmnJsonConverter implements EditorJsonConstants, StencilConstants, ActivityProcessor {
protected static Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap = new HashMap<>();
protected static Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap = new HashMap<>();
...
static {
        ... 
// task types
        ... 
UserTaskJsonConverter.fillTypes(convertersToBpmnMap, convertersToJsonMap);
...
}
...
}

debug如下在项目启动时,将UserTaskJsonConverter UserTask元素的转换器注入到BpmnModel和Bpmn Json相互转换的两个静态map中。

所以我们如何想要实现对UserTask元素进行扩展属性,重写UserTaskJsonConverter的BpmnModel和bpmn Json的转换方法即可,如下是扩展实现:

//自定义UserTaskJsonConverter:
public class CustomUserTaskJsonConverter extends UserTaskJsonConverter {
   
   //注入自定义CustomUserTaskJsonConverter
static void customFillTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap, Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
fillJsonTypes(convertersToBpmnMap);
fillBpmnTypes(convertersToJsonMap);
}


public static void fillJsonTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap) {
convertersToBpmnMap.put(STENCIL_TASK_USER, CustomUserTaskJsonConverter.class);
}


public static void fillBpmnTypes(Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
convertersToJsonMap.put(UserTask.class, CustomUserTaskJsonConverter.class);
}

    //重写UserTask Element和Json转换方法
@Override
protected void convertElementToJson(ObjectNode propertiesNode, BaseElement baseElement) {
super.convertElementToJson(propertiesNode, baseElement);
//获取扩展属性并进行设置
UserTask userTask = (UserTask) baseElement;
Map<String, List<ExtensionAttribute>> attributes = userTask.getAttributes();
for (Map.Entry<String, List<ExtensionAttribute>> entry : attributes.entrySet()) {
String key = entry.getKey();
String value = entry.getValue().get(0).getValue();
            //自定义属性
if (key.equalsIgnoreCase("customArr")) {
propertiesNode.put("customArr", value);
continue;
            }
}
}

//重写Json和UserTask Element转换方法
@Override
protected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode, Map<String, JsonNode> shapeMap) {
return super.convertJsonToElement(elementNode, modelNode, shapeMap);
}


@Override
protected void convertJsonToFormProperties(JsonNode objectNode, BaseElement element) {
super.convertJsonToFormProperties(objectNode, element);
if (element instanceof UserTask) {
UserTask userTask = (UserTask) element;
//将Json转为UserTask中的Element
            String customArr= BpmnJsonConverterUtil.getPropertyValueAsString("customArr", objectNode);
   
if (StringUtils.isNotEmpty(customArr)) {
                ExtensionAttribute customArrExtensionAttribute = new ExtensionAttribute();
customArrExtensionAttribute.setName("customArr");
customArrExtensionAttribute.setValue(nodeClassType);
customArrExtensionAttribute.setNamespace("http://flowable.org/bpmn");
customArrExtensionAttribute.setNamespacePrefix("flowable");
userTask.addAttribute(customArrExtensionAttribute);
            }
}
}
}
至此完成了UserTask元素中自定义属性的实现~~

长按二维码关注我们

ITSK

博客|yajing8


我知道你在看

文章转载自ITSK,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论