Activiti6.0 (9) integrated custom online process designer (used by BpmnModel)

table of Contents

I. Introduction

2. Integration


I. Introduction

All the previous examples are based on the Activiti-app online flow chart drawing, then exported as an xml file, and finally deployed to the database as an external resource. Although this method is very powerful, it is not easy to integrate. Some existing online The process editor is really too complicated and ugly, and users don't need to configure so many things.

Therefore, when the process design process is handed over to the user, the user definitely needs a beautiful and concise process designer. Then the company will find the appropriate open source tool or develop a front-end flowchart component by itself. Our company has used it before. Developed a simple flowchart component, then how to define the data format of the entire flowchart? How to deploy to Activiti after definition?

 

2. Integration

Before integration, we definitely need to get the json data first, and the flow chart data structure transparently transmitted from the front end can be customized with various business information, but we need to be converted to the Activiti layer. The custom json data is converted into the data recognized by Activiti. We can actually get the data format of Activiti's flowchart. Just press f12 to view the save request when Activiti-app is saved. Hahahahaha, isn't it simple? Is there a general idea? Here is a super simple flowchart and the corresponding json data (in order to save space, the json data can be formatted by yourself):

{"resourceId":"5c5040fe-b196-433d-b34e-3d01cd6c85dc","properties":{"process_id":"simpleModel","name":"简单流程","documentation":"","process_author":"","process_version":"","process_namespace":"http://www.activiti.org/processdef","executionlisteners":"","eventlisteners":"","signaldefinitions":"","messagedefinitions":""},"stencil":{"id":"BPMNDiagram"},"childShapes":[{"resourceId":"startEvent1","properties":{"overrideid":"","name":"","documentation":"","executionlisteners":"","initiator":"","formkeydefinition":"","formreference":"","formproperties":""},"stencil":{"id":"StartNoneEvent"},"childShapes":[],"outgoing":[{"resourceId":"sid-1007C45C-AB28-4EA8-87C9-0E35B6FFA141"}],"bounds":{"lowerRight":{"x":130,"y":193},"upperLeft":{"x":100,"y":163}},"dockers":[]},{"resourceId":"sid-584C69B4-A76F-4396-8FE1-1FC77C0385CC","properties":{"overrideid":"","name":"组长审批","documentation":"","asynchronousdefinition":"false","exclusivedefinition":"false","executionlisteners":"","multiinstance_type":"None","multiinstance_cardinality":"","multiinstance_collection":"","multiinstance_variable":"","multiinstance_condition":"","isforcompensation":"false","usertaskassignment":{"assignment":{"type":"idm","idm":{"type":"users","candidateUsers":[{"id":"test","firstName":"test","lastName":null,"email":null,"fullName":"test ","groups":[],"$$hashKey":"object:6687"}]}}},"formkeydefinition":"","formreference":"","duedatedefinition":"","prioritydefinition":"","formproperties":"","tasklisteners":""},"stencil":{"id":"UserTask"},"childShapes":[],"outgoing":[{"resourceId":"sid-CD98690F-4EA7-4F5F-9A04-FC604815AD2B"}],"bounds":{"lowerRight":{"x":332,"y":216},"upperLeft":{"x":232,"y":136}},"dockers":[]},{"resourceId":"sid-5D1AABEF-2AB6-46E9-9AD5-0CD36AD6251C","properties":{"overrideid":"","name":"","documentation":"","executionlisteners":""},"stencil":{"id":"EndNoneEvent"},"childShapes":[],"outgoing":[],"bounds":{"lowerRight":{"x":493,"y":193},"upperLeft":{"x":465,"y":165}},"dockers":[]},{"resourceId":"sid-1007C45C-AB28-4EA8-87C9-0E35B6FFA141","properties":{"overrideid":"","name":"","documentation":"","conditionsequenceflow":"","executionlisteners":"","defaultflow":"false"},"stencil":{"id":"SequenceFlow"},"childShapes":[],"outgoing":[{"resourceId":"sid-584C69B4-A76F-4396-8FE1-1FC77C0385CC"}],"bounds":{"lowerRight":{"x":231.4219467051485,"y":177.8161498108401},"upperLeft":{"x":130.3514907948515,"y":176.6057251891599}},"dockers":[{"x":15,"y":15},{"x":50,"y":40}],"target":{"resourceId":"sid-584C69B4-A76F-4396-8FE1-1FC77C0385CC"}},{"resourceId":"sid-CD98690F-4EA7-4F5F-9A04-FC604815AD2B","properties":{"overrideid":"","name":"","documentation":"","conditionsequenceflow":"","executionlisteners":"","defaultflow":"false"},"stencil":{"id":"SequenceFlow"},"childShapes":[],"outgoing":[{"resourceId":"sid-5D1AABEF-2AB6-46E9-9AD5-0CD36AD6251C"}],"bounds":{"lowerRight":{"x":464.14855343232165,"y":178.7738358390709},"upperLeft":{"x":332.24988406767835,"y":176.7652266609291}},"dockers":[{"x":50,"y":40},{"x":14,"y":14}],"target":{"resourceId":"sid-5D1AABEF-2AB6-46E9-9AD5-0CD36AD6251C"}}],"bounds":{"lowerRight":{"x":1200,"y":1050},"upperLeft":{"x":0,"y":0}},"stencilset":{"url":"stencilsets/bpmn2.0/bpmn2.0.json","namespace":"http://b3mn.org/stencilset/bpmn2.0#"},"ssextensions":[]}

Now that the data format is available, what remains is to take out part of our custom flow chart data and convert part of the non-business data into Activiti data to ensure that the engine can flow normally. Corresponding to the above data, we abstract the corresponding entity class:

public class ChartElement {

    /**
     * 资源ID
     */
    private String resourceId = "";
    /**
     * 属性,这是最关键的,每一个元素都拥有不同的属性项,如线对象、用户任务对象、网关对象等等,以继承方式实现即可
     */
    private BaseProperty properties;
    /**
     * 流程环节的activiti类型
     * key为id
     * 形似:
     * "stencil": {
            "id": "BPMNDiagram"
        }
     */
    private Map<String, String> stencil = new HashMap<>();
    /**
     * 子组件
     */
    private List<ChartElement> childShapes = new ArrayList<>();
    /**
     * 组件外连的其他组件Id
     * 形似:
     * "outgoing": [
            {
                "resourceId": "sid-F642A425-567D-4D05-9861-E04640D0E4E5"
            },
            {
                "resourceId": "sid-F642A425-567D-4D05-9861-E04640D0E4E5"
            }
        ]
     */
    private List<Map<String, String>> outgoing = new ArrayList<>();
    /**
     * 组件所在位置。
     * 形似:
     * "bounds": {
            "lowerRight": {
                "x": 324.64844687000755,
                "y": 189.4097335362338
            },
            "upperLeft": {
            "x": 280.62889687999245,
            "y": 189.2191727137662
            }
        }
     * lowerRight:组件的右下角坐标
     * upperLeft:组件的左上角坐标
     */
    private Map<String, Coordinate> bounds = new HashMap<>();
    /**
     * 连接线上的拐点坐标
     * 形似:
     * "dockers": [
             {
                 "x": 50,
                 "y": 40
             },
             {
                 "x": 20.5,
                 "y": 20.5
             }
        ]
     */
    private List<Coordinate> dockers = new ArrayList<>();
    /**
     * 连接线的目标组件ID
     * 形如:
     * "target": {
            "resourceId": "sid-AB6219CA-5A68-4CFC-A7E1-D8F7D6375519"
        }
     */
    private Map<String, String> target = new HashMap<>();

}



public class BaseProperty {
    /**
     * 名称
     */
    private String name = "";
    /**
     * 说明
     */
    private String document = "";
}



public class UserTaskProperty extends BaseProperty {
    /**
     * 异步操作标识符,默认false
     */
    @JsonProperty("asynchronousdefinition")
    private boolean asynchronousDefinition;
    /**
     * 排他属性,默认false
     */
    @JsonProperty("exclusivedefinition")
    private boolean exclusiveDefinition;
    /**
     * 多例模式(会签)
     * {@linkplain uyun.hornet.config.api.enums.MultiInstanceType#code}
     */
    @JsonProperty("multiinstance_type")
    private String multiInstanceType = "";
    /**
     * 会签状态下,需要分配的人员集合
     */
    @JsonProperty("multiinstance_collection")
    private String multiInstanceCollection = "";
    /**
     * 会签状态下,变量
     */
    @JsonProperty("multiinstance_variable")
    private String multiInstanceVariable = "";
    /**
     * 用户任务分配的人员
     */
    @JsonProperty("usertaskassignment")
    private Map<String, Map<String, String>> usertaskAssignment = new HashMap<>();
    /**
     * 人工任务的监听器,主要是为了自动节点和子流程节点使用
     */
    @JsonProperty("tasklisteners")
    private Map<String, List<TaskListenerBean>> tasklisteners = new HashMap<>();

    public void setTasklisteners(String delegateExpression) {
        List<TaskListenerBean> taskListenerBeans = new ArrayList<>();
        TaskListenerBean taskListenerBean = new TaskListenerBean();
        taskListenerBean.setEvent("create");
        taskListenerBean.setDelegateExpression(delegateExpression);
        taskListenerBean.setImplementation(delegateExpression);
        taskListenerBeans.add(taskListenerBean);
        Map<String, List<TaskListenerBean>> listen = new HashMap<>();
        listen.put("taskListeners", taskListenerBeans);
        this.tasklisteners = listen;
    }

    class TaskListenerBean{
        /**
         * 事件类型
         */
        private String event;
        /**
         * 实现类
         */
        private String implementation;
        /**
         * className
         */
        private String className;
        /**
         * 表达式
         */
        private String expression;
        /**
         * 委托表达式
         */
        private String delegateExpression;

    }
}

The relevant classes in the abstract class have been put up, mainly based on the json data of the model to abstract, and different attributes need to be assigned to different element objects during encapsulation. For details, please refer to the retention format of Activiti-app. That is, it is best to expand the json data, and then compare it.

It is assumed here that you have already converted and got a complete flow chart object ChartElement. The remaining steps are to convert the object to BpmnModel. We don’t need to convert it manually. There are tools to help us realize it. You can use it directly. First, introduce Corresponding dependencies:

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.5</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-json-converter</artifactId>
            <version>6.0.0</version>
        </dependency>

Then use the following code:

@Test
    public void transformChartTest() throws Exception {
        // 假设这是你已经转换好后的整个流程图对象
        ChartElement chartElement = new ChartElement();
        // 这里借助jackson库来转换
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonNode = mapper.readTree(mapper.writeValueAsString(chartElement));
        // 然后借助工具将jsonNod转换成BpmnModel
        BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
        // 最后直接部署即可,注意流程id不能以数字开头
        repositoryService.createDeployment().addBpmnModel("sid-123.bpmn20.xml", bpmnModel).deploy();
    }

For some special nodes, if you need to add a listener, the conversion method can be consistent with the interface. You can use a delegate expression to achieve it, such as: ${Listener service class}, the service class only needs to be injected by spring can.

This is the end, you can directly start the process example~ The information on the Internet was sparse and it was painful when looking for it. Here is a special sharing. At this point in the series, Activiti can be used to achieve most of the functions including integrating your own company. Flow chart editor.

 

-2020/7/14 update entity class

 

If the series is helpful to you, you can ask the blogger to have a cup of coffee hee hee

(Left Alipay, Right WeChat)

Guess you like

Origin blog.csdn.net/m0_38001814/article/details/104209360