springboot保存bpmn文件及用户自定义参数的保存与获取

假如有如下一份bpmn文件,其中usertask扩展了多个属性,那么如何对其进行保存和获取呢?

Tall is cheap, show you the code!

1.准备

假定bpmn如下:

实例流程

代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions
    xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:activiti="http://activiti.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"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://bpmn.io/schema/bpmn">
    <bpmn2:process id="p_1367770574455656450" name="jh0305" isExecutable="true">
        <bpmn2:documentation>jh0305</bpmn2:documentation>
        <bpmn2:startEvent id="Event_1" name="开始">
            <bpmn2:outgoing>SequenceFlow_11hdsvi</bpmn2:outgoing>
        </bpmn2:startEvent>
        <bpmn2:userTask id="UserTask_0ag1sf3" name="用户任务1" activiti:priority="0">
            <bpmn2:extensionElements>
                <activiti:customProperties assigneeType="0" />
            </bpmn2:extensionElements>
        </bpmn2:userTask>
        <bpmn2:sequenceFlow id="SequenceFlow_11hdsvi" sourceRef="Event_1" targetRef="UserTask_0ag1sf3" />
        <bpmn2:userTask id="Activity_10ovq4m" name="用户任务_2" activiti:formKey="" activiti:priority="1">
            <bpmn2:extensionElements>
                <activiti:customProperties assigneeType="1"/>
            </bpmn2:extensionElements>
        </bpmn2:userTask>
        <bpmn2:endEvent id="Event_0jg7oml" name="结束节点_0">
            <bpmn2:incoming>Flow_1hr1bdj</bpmn2:incoming>
        </bpmn2:endEvent>
        <bpmn2:sequenceFlow id="Flow_116afj0" sourceRef="UserTask_0ag1sf3" targetRef="Activity_10ovq4m" />
        <bpmn2:sequenceFlow id="Flow_1hr1bdj" sourceRef="Activity_10ovq4m" targetRef="Event_0jg7oml" />
    </bpmn2:process>
    <bpmndi:BPMNDiagram id="BPMNDiagram_p_1367770574455656450">
        <bpmndi:BPMNPlane id="BPMNPlane_p_1367770574455656450" bpmnElement="p_1367770574455656450">
            <bpmndi:BPMNEdge id="BPMNEdge_Flow_1hr1bdj" bpmnElement="Flow_1hr1bdj">
                <omgdi:waypoint x="790" y="258" />
                <omgdi:waypoint x="852" y="258" />
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="BPMNEdge_Flow_116afj0" bpmnElement="Flow_116afj0">
                <omgdi:waypoint x="620" y="258" />
                <omgdi:waypoint x="690" y="258" />
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge id="BPMNEdge_SequenceFlow_11hdsvi" bpmnElement="SequenceFlow_11hdsvi">
                <omgdi:waypoint x="448" y="258" />
                <omgdi:waypoint x="520" y="258" />
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNShape id="BPMNShape_Event_1" bpmnElement="Event_1">
                <omgdc:Bounds x="412" y="240" width="36" height="36" />
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="BPMNShape_UserTask_0ag1sf3" bpmnElement="UserTask_0ag1sf3">
                <omgdc:Bounds x="520" y="218" width="100" height="80" />
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="BPMNShape_Activity_10ovq4m" bpmnElement="Activity_10ovq4m">
                <omgdc:Bounds x="690" y="218" width="100" height="80" />
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape id="BPMNShape_Event_0jg7oml" bpmnElement="Event_0jg7oml">
                <omgdc:Bounds x="852" y="240" width="36" height="36" />
            </bpmndi:BPMNShape>
        </bpmndi:BPMNPlane>
    </bpmndi:BPMNDiagram>
</bpmn2:definitions>

注意:两个用户任务节点中的

<bpmn2:extensionElements>
    <activiti:customProperties assigneeType="0" />
</bpmn2:extensionElements>

activiti:customProperties即为自定义节点,其中有一个assigneeType属性

2.保存bpmn文件

使用了swagger和lombok

2.1 前端传输的对象模型

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;

@Getter
@Setter
@ApiModel("流程模型对象")
public class BpmnModelVO implements Serializable {
    @ApiModelProperty("bpmn文件的xml字符串")
    String bpmnXml;
    @ApiModelProperty("流程名称")
    String name;
    @ApiModelProperty("流程的key")
    Long processKey;
    @ApiModelProperty("租户id")
    String tenantId;
    @ApiModelProperty(value = "模型id,新增时为空")
    String modelId;
}

2.2 自定义消息转换方法

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.bpmn.model.*;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class MyUserTaskJsonConverter extends UserTaskJsonConverter{
    private final String assigneeType = "assigneeType";
    private final String elememt = "customProperties";
    /**
    * 将bpmn元素转换成json
    */
    @Override
    protected void convertElementToJson(ObjectNode propertiesNode, BaseElement baseElement) {
        super.convertElementToJson(propertiesNode, baseElement);
        UserTask userTask = (UserTask) baseElement;
        //解析
        Map<String, List<ExtensionElement>> customerProperties = userTask.getExtensionElements();
        if (!CollectionUtils.isEmpty(customerProperties) && customerProperties.containsKey(elememt)) {
            ExtensionElement e = customerProperties.get(elememt).get(0);
            Map<String, List<ExtensionAttribute>> attributes = e.getAttributes();
            attributes.forEach((key, attr) -> {
                for (ExtensionAttribute extensionAttribute : attr) {
                    setPropertyValue(extensionAttribute.getName(), extensionAttribute.getValue(), propertiesNode);
                }
            });
        }
    }
    
    /**
    * 将json转换成bpmn元素
    */
    @Override
    protected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode, Map<String, JsonNode> shapeMap) {
        FlowElement flowElement = super.convertJsonToElement(elementNode,
                modelNode, shapeMap);
        //解析新增属性的业务逻辑
        UserTask userTask = (UserTask) flowElement;

        ExtensionElement ee = new ExtensionElement();
        ee.setName("activiti:" + elememt);
        ee.setNamespacePrefix("activiti");
        Map<String, List<ExtensionAttribute>> attributes = new HashMap<>();
        // 这里就是bpmn里自定义的assigneeType
        String propertyAssigneeType = getPropertyValueAsString(assigneeType, elementNode);
        if (StringUtils.hasLength(propertyAssigneeType)) {
            ExtensionAttribute assigneeTypeAttr = new ExtensionAttribute();
            assigneeTypeAttr.setName(assigneeType);
            assigneeTypeAttr.setValue(propertyAssigneeType);
            List<ExtensionAttribute> assigneeTypeList = new ArrayList<>(1);
            assigneeTypeList.add(assigneeTypeAttr);
            attributes.put(assigneeType, assigneeTypeList);
        }
        ee.setAttributes(attributes);

        userTask.addExtensionElement(ee);
        return userTask;
    }
}

2.3 实现BpmnJsonConverter,替换转换方法

public class CustomBpmnJsonConverter extends BpmnJsonConverter {

    public static void initCustomJsonConverter() {
        convertersToBpmnMap.put(STENCIL_TASK_USER, MyUserTaskJsonConverter.class);
        convertersToJsonMap.put(UserTask.class, MyUserTaskJsonConverter.class);
    }
}

2.4 配置

@Configuration
public class ActivitiAutoConfiguration implements ProcessEngineConfigurationConfigurer {

    @Override
    public void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) {
        // 其他配置
        // 配置自定义用户任务解析器
        CustomBpmnJsonConverter.initCustomJsonConverter();
    }
}

2.5 controller类

@RestController
@RequestMapping("model")
@Api(tags = "流程模型接口")
public class ModelController {

    private final RepositoryService repositoryService;
    private final ObjectMapper objectMapper;

    public ModelController(RepositoryService repositoryService, ObjectMapper objectMapper) {
        this.repositoryService = repositoryService;
        this.objectMapper = objectMapper;
    }

    @PostMapping("/save")
    @ApiOperation("保存模型")
    public ResponseResult<String> saveBpmn(@RequestBody BpmnModelVO bpmn) {
        if (bpmn == null || StringUtils.isEmpty(bpmn.getBpmnXml()) || StringUtils.isEmpty(bpmn.getTenantId())
                || StringUtils.isEmpty(bpmn.getProcessKey()) || StringUtils.isEmpty(bpmn.getName()))
            return ResponseResult.error("参数不完整");
        Model modelData = null;
        if (StringUtils.hasLength(bpmn.getModelId()))
            modelData = repositoryService.getModel(bpmn.getModelId());
        if (modelData == null) {
            modelData = repositoryService.newModel();
        }
        //与前端保持一致
        modelData.setKey("p_" + bpmn.getProcessKey());
        modelData.setName(bpmn.getName());
        modelData.setTenantId(bpmn.getTenantId());
        try {
            XMLInputFactory xif = XMLInputFactory.newInstance();
            InputStream is = new ByteArrayInputStream(bpmn.getBpmnXml().getBytes(StandardCharsets.UTF_8));
            XMLStreamReader xtr = xif.createXMLStreamReader(is);
            // 转为bpmnModel
            BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
            // bpmnModel转json
            CustomBpmnJsonConverter converter = new CustomBpmnJsonConverter();
            ObjectNode jsonNodes = converter.convertToJson(bpmnModel);
            ObjectMapper objectMapper = new ObjectMapper();
            String jsonXml = objectMapper.writeValueAsString(jsonNodes);
            this.flowService.saveModel(repositoryService, modelData, jsonXml, bpmn.getProcessKey());
        } catch (XMLStreamException | JsonProcessingException e) {
            e.printStackTrace();
            return ResponseResult.error(e.getMessage());
        }
        return ResponseResult.success(modelData.getId());
    }

    @GetMapping("/getById/{modelId}")
    @ApiOperation("根据模型id获取模型bpmn的xml字符串")
    public ResponseResult<String> getBpmnXmnById(@ApiParam(value = "bpmn模型id", required = true) @PathVariable("modelId") String modelId) {
        Model modelData = repositoryService.getModel(modelId);
        if (modelData != null)
            try {
                byte[] modelEditorSource = repositoryService.getModelEditorSource(modelData.getId());
                ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(modelEditorSource);
                CustomBpmnJsonConverter converter = new CustomBpmnJsonConverter();
                BpmnModel model = converter.convertToBpmnModel(modelNode);// 转model
                byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);// 转xml
                return ResponseResult.success(new String(bpmnBytes));
            } catch (IOException e) {
                e.printStackTrace();
                return ResponseResult.error("获取失败");
            }
        return ResponseResult.error("不存在该模型");
    }
}

2.6 ResponseResult类

@Data
public class ResponseResult<T> {
	
	private int code;
	
	private String msg;

	private T data;

    private ResponseResult(){}

    public ResponseResult(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    private ResponseResult(ResultCode resultCode) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
    }

    private ResponseResult(ResultCode resultCode, T data) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
        this.data = data;
    }

    public static <T> ResponseResult<T> success() {
        return new ResponseResult<>(ResultCode.SUCCESS);
    }

	public static <T> ResponseResult<T> success(T data) {
		return new ResponseResult<>(ResultCode.SUCCESS, data);
	}

	public static <T> ResponseResult<T> error(ResultCode resultCode) {
		return new ResponseResult<>(resultCode);
	}

    public static <T> ResponseResult<T> error(String msg) {
        return new ResponseResult<>(ResultCode.FAIL.getCode(), msg);
    }
}

以上即为bpmn文件的保存与获取,以及用户任务自定义属性设置的参考做法。如有疏漏恭请指正。

 

欢迎来我的个人网站逛逛:往后码生

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中集成BPMN(Business Process Model and Notation)可以使用Camunda BPM引擎。Camunda BPM是一个开源的工作流引擎,它提供了强大的BPMN支持。 下面是在Spring Boot中集成Camunda BPM的步骤: 1. 添加Camunda BPM依赖:在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.camunda.bpm.springboot</groupId> <artifactId>camunda-bpm-spring-boot-starter</artifactId> <version>${camunda.version}</version> </dependency> ``` 2. 创建BPMN流程定义文件:在src/main/resources目录下创建一个以.bpmn为后缀的BPMN文件,定义你的业务流程。 3. 创建Spring Boot主类:创建一个带有@SpringBootApplication注解的Spring Boot主类。 4. 配置Camunda BPM引擎:在application.properties或application.yml文件中添加以下配置: ```properties spring.datasource.url=jdbc:h2:mem:camunda;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE spring.datasource.username=sa spring.datasource.password= spring.datasource.driver-class-name=org.h2.Driver spring.jpa.database-platform=org.hibernate.dialect.H2Dialect ``` 5. 启用Camunda BPM引擎:在主类上添加@EnableProcessApplication注解,以启用Camunda BPM引擎。 ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.camunda.bpm.spring.boot.starter.annotation.EnableProcessApplication; @SpringBootApplication @EnableProcessApplication public class MyApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } } ``` 6. 运行应用程序:运行Spring Boot应用程序,Camunda BPM引擎将会自动加载并部署你定义的BPMN流程。 这样,你就成功地将BPMN集成到了Spring Boot应用程序中。你可以使用Camunda BPM提供的API来管理和执行你的BPMN流程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值