工具

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
  1. 新建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");
            }
        }
    }
}

  1. 新建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();
}
  1. 新建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);
    }
}
  1. 新建自定义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;
    }
}

  1. 创建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

到这里我们已经成功获取到了,希望对大家有帮助。不对的地方还请指出。

上一篇下一篇

猜你喜欢

热点阅读