美文网首页工具
flowable modeler自定义属性,并且在流程中获取属性

flowable modeler自定义属性,并且在流程中获取属性

作者: IPYJ | 来源:发表于2019-12-18 21:25 被阅读0次

    因为自己系统中业务的需求,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

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

    相关文章

      网友评论

        本文标题:flowable modeler自定义属性,并且在流程中获取属性

        本文链接:https://www.haomeiwen.com/subject/zxhpnctx.html