flowable modeler自定义属性,并且在流程中获取属性
2019-12-18 本文已影响0人
IPYJ
因为自己系统中业务的需求,flowable节点自带的属性是有限的,所以需要在节点上自定义属性以便于流程流转。
一、修改stencilset_bpmn.json
{
"name" : "approvalPathPackage",
"properties" : [ {
"id" : "approvalPath",
"type" : "Text",
"title" : "审批接口路径",
"value" : "",
"description" : "The descriptive name of the BPMN element.",
"popular" : true
} ]
},
{
"name" : "rejectPathPackage",
"properties" : [ {
"id" : "rejectPath",
"type" : "Text",
"title" : "驳回接口路径",
"value" : "",
"description" : "The descriptive name of the BPMN element.",
"popular" : true
} ]
},
在文件下面添加上面配置的name
4.png 3.png
但是只是这样配好之后我们去下载xml的时候会发现没有新增的属性,这个时候在流程实例流转的时候也是获取不到新增属性的值的。
是因为flowable并没有支持自定义属性的存储,所以这个时候就要自己对自定义属性进行解析了。
二、现在就要修改下载xml文件那个接口,路径前的custom是我自己加进去的,重写这个接口
2.png
- 新建ModelController 继承 AbstractModelBpmnResource:
package com.chinairi.workflow.modeler.controller;
import com.chinairi.workflow.modeler.service.CustomModelServiceImpl;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.ui.common.service.exception.BadRequestException;
import org.flowable.ui.common.service.exception.BaseModelerRestException;
import org.flowable.ui.common.service.exception.InternalServerErrorException;
import org.flowable.ui.modeler.domain.AbstractModel;
import org.flowable.ui.modeler.domain.Model;
import org.flowable.ui.modeler.rest.app.AbstractModelBpmnResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URLEncoder;
/**
* @author PYJ
* @date 2019/12/13
*/
@RestController
@RequestMapping("/custom/app")
public class ModelController extends AbstractModelBpmnResource {
private static final Logger LOGGER = LoggerFactory.getLogger(ModelController.class);
@Autowired
protected CustomModelServiceImpl xxModelService;
/**
* GET /rest/models/{modelId}/bpmn20 -> Get BPMN 2.0 xml
*/
@RequestMapping(value = "/rest/models/{processModelId}/bpmn20", method = RequestMethod.GET)
public void getProcessModelBpmn20Xml(HttpServletResponse response, @PathVariable String processModelId) throws IOException {
LOGGER.info("开始下载xml文件1");
if (processModelId == null) {
throw new BadRequestException("No process model id provided");
}
Model model = xxModelService.getModel(processModelId);
generateBpmn20Xml(response, model);
}
protected void generateBpmn20Xml(HttpServletResponse response, AbstractModel model) {
String name = model.getName().replaceAll(" ", "_") + ".bpmn20.xml";
String encodedName = null;
try {
encodedName = "UTF-8''" + URLEncoder.encode(name, "UTF-8");
} catch (Exception e) {
LOGGER.warn("Failed to encode name " + name);
}
String contentDispositionValue = "attachment; filename=" + name;
if (encodedName != null) {
contentDispositionValue += "; filename*=" + encodedName;
}
response.setHeader("Content-Disposition", contentDispositionValue);
if (model.getModelEditorJson() != null) {
try {
ServletOutputStream servletOutputStream = response.getOutputStream();
response.setContentType("application/xml");
BpmnModel bpmnModel = xxModelService.getBpmnModel(model);
byte[] xmlBytes = xxModelService.getBpmnXML(bpmnModel);
BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(xmlBytes));
byte[] buffer = new byte[8096];
while (true) {
int count = in.read(buffer);
if (count == -1) {
break;
}
servletOutputStream.write(buffer, 0, count);
}
// Flush and close stream
servletOutputStream.flush();
servletOutputStream.close();
} catch (BaseModelerRestException e) {
throw e;
} catch (Exception e) {
LOGGER.error("Could not generate BPMN 2.0 XML", e);
throw new InternalServerErrorException("Could not generate BPMN 2.0 xml");
}
}
}
}
- 新建CustomModelServiceImpl继承 ModelServiceImpl
package com.chinairi.workflow.modeler.service;
import com.chinairi.workflow.modeler.convert.CustomBpmnJsonConverter;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.ui.modeler.service.ModelServiceImpl;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
/**
* @author PYJ
* @date 2019/12/13
*/
@Service("CustomModelServiceImpl")
@Primary
public class CustomModelServiceImpl extends ModelServiceImpl {
protected BpmnJsonConverter bpmnJsonConverter = new CustomBpmnJsonConverter();
}
- 新建CustomBpmnJsonConverter继承 BpmnJsonConverter
package com.chinairi.workflow.modeler.convert;
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
/**
* @author PYJ
* @date 2019/12/13
*/
public class CustomBpmnJsonConverter extends BpmnJsonConverter {
static {
convertersToBpmnMap.put(STENCIL_TASK_USER,CustomizeUserTaskJsonConverter.class);
}
}
- 新建自定义userTaskjson解析器CustomizeUserTaskJsonConverter继承UserTaskJsonConverter
package com.chinairi.workflow.modeler.convert;
import com.chinairi.workflow.modeler.util.ExtensionAttributeUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.flowable.bpmn.model.BaseElement;
import org.flowable.bpmn.model.ExtensionAttribute;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.editor.language.json.converter.BaseBpmnJsonConverter;
import org.flowable.editor.language.json.converter.UserTaskJsonConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* @author PYJ
* @date 2019/12/13
*/
public class CustomizeUserTaskJsonConverter extends UserTaskJsonConverter {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomizeUserTaskJsonConverter.class);
//审批接口路径配置
private static final String TASK_APPROVAL_PATH="approvalpath";
private static final String TASK_APPROVAL_PATH_KEY="approvalPath";
//驳回接口路径设置
private static final String TASK_REJECT_PATH="rejectpath";
private static final String TASK_REJECT_PATH_KEY="rejectPath";
public static void fillBpmnTypes(
Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
convertersToJsonMap.put(UserTask.class, CustomizeUserTaskJsonConverter.class);
}
@Override
protected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode,
Map<String, JsonNode> shapeMap) {
FlowElement flowElement = super.convertJsonToElement(elementNode, modelNode, shapeMap);
LOGGER.info("进入自定义属性解析");
if(flowElement instanceof UserTask){
ObjectMapper objectMapper = new ObjectMapper();
UserTask userTask = (UserTask) flowElement;
try {
LOGGER.info("节点:" + objectMapper.writeValueAsString(userTask));
}catch (JsonProcessingException e) {
LOGGER.error("节点序列化异常.");
}
Map<String,List<ExtensionAttribute>> atts = new HashMap<String,List<ExtensionAttribute>>();
String approvalPath = getPropertyValueAsString(TASK_APPROVAL_PATH,elementNode);
LOGGER.info("新增自定义审批接口路径;路径属性["+TASK_APPROVAL_PATH+"]="+approvalPath);
ExtensionAttribute ea1 = ExtensionAttributeUtils.generate(TASK_APPROVAL_PATH_KEY,approvalPath);
String rejectPath = getPropertyValueAsString(TASK_REJECT_PATH,elementNode);
LOGGER.info("新增自定义驳回接口路径;路径属性["+TASK_REJECT_PATH+"]="+rejectPath);
ExtensionAttribute ea2 = ExtensionAttributeUtils.generate(TASK_REJECT_PATH_KEY,rejectPath);
List<ExtensionAttribute> list = new ArrayList<>();
if (ea1 != null){
list.add(ea1);
}
if (ea2 != null){
list.add(ea2);
}
atts.put("CUSTOM-FLOWABLE-EXT",list);
if (atts.size()>0){
flowElement.setAttributes(atts);
}
}
return flowElement;
}
}
- 创建ExtensionAttributeUtils 对 拓展属性进行操作
package com.chinairi.workflow.modeler.util;
import org.flowable.bpmn.model.ExtensionAttribute;
/**
* @author PYJ
* @date 2019/12/13
*/
public class ExtensionAttributeUtils {
public static ExtensionAttribute generate(String key, String val){
ExtensionAttribute ea = new ExtensionAttribute();
ea.setNamespace("http://xx.com.cn");
ea.setName(key);
ea.setNamespacePrefix("custom");
ea.setValue(val);
return ea;
}
}
重新部署之后再下载xml 可以看到已经有了我们自定义的属性
5.png
三、接下来就是在流程中获取自定义属性值
public Map<String, List<ExtensionAttribute>> getZidiyingParam(String taskId){
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null){
return null;
}
Map<String, List<ExtensionAttribute>> extensionAttrs = null;
String processDefId = task.getProcessDefinitionId();
FlowNode flowNode = findFlowNodeByActivityId(processDefId,task.getTaskDefinitionKey());
if (flowNode != null && flowNode instanceof UserTask) {
UserTask userTask = (UserTask) flowNode;
extensionAttrs = userTask.getAttributes();
}
for (String key : extensionAttrs.keySet()){
System.out.println("====");
System.out.println("key:"+key);
System.out.println(extensionAttrs.get(key));
System.out.println(extensionAttrs.get(key).get(0).getValue());
}
return extensionAttrs;
}
public FlowNode findFlowNodeByActivityId(String processDefId, String activityId) {
FlowNode activity = null;
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId);
List<Process> processes = bpmnModel.getProcesses();
for (Process process : processes) {
FlowElement flowElement = process.getFlowElementMap().get(activityId);
if (flowElement != null) {
activity = (FlowNode) flowElement;
break;
}
}
return activity;
}
接下来可以看到输出的结果,和流程设计的时候输入的自定义属性值一样的
6.png
到这里我们已经成功获取到了,希望对大家有帮助。不对的地方还请指出。