“Work order system” from the macro point of view, is some state flow transformation, the author believes that the implementation of work order system is the realization of workflow (Workflow), typical application of enterprise OA system, all kinds of CRM, ERP and so on.

For the realization of work order system, in fact, we can combine the actual business to write the corresponding business code, the biggest benefit of doing so is a high degree of customization, the operation of business process is highly customized. However, when things go too far, highly customized business processes lose some flexibility.

So the question is: how?

Answer: Based on industry standards.

Standard = Authority

We have to be suspicious when we find that our designed business processes do not meet standards.


It’s time for a workflow killer: BPMN2.0

As for the basic introduction of BPMN2.0, I will not repeat it here, but summarize it in one sentence: BPMN2.0 is a complete set of workflow development standards developed by IBM, which includes various basic elements such as events, gateways, sequential flows, tasks, and so on.

After all, BPMN2.0 is only a set of standards, but also needs to be implemented. The well-known workflow development framework in the industry should be Activiti. The programming language used is Java, which is widely used.

If you are going to get into workflow development, either using frameworks or developing your own, it is recommended that you read this document, which is very helpful for actual development work.

Going back to the “work order system” mentioned at the beginning of the article, let’s talk about some of my personal thoughts on starting this project.

The process promotion of work order itself is an embodiment of workflow, so it is natural to use the standard of BPMN2.0. After a working day or so of poring over the reference documents mentioned above, it became clear that the subtleties of the BPMN2.0 standard were more than adequate to cover existing business requirements.

Of course, when doing the system architecture, it must be combined with the actual business requirements. After careful analysis of my own business requirements, I found that they were all “short processes”, with no more than 2 work order tasks and only one work order task type (namely, userTask), and few process branches. In a word, the author was faced with some relatively simple work order processes.

If we directly use a large and complex framework like Acviti, on the one hand, the actual work order process is not complicated, and on the other hand, it is overqualified. Moreover, team members are not familiar with this standard, so it is difficult to understand and connect with it.

Therefore, the author embarked on the road based on BPMN2.0 standard research.

It was not an ambition to reinvent Activiti, but rather a feature tailoring of Activiti that only implemented the necessary standards.

The architectural design of this workorder system will be explained in three articles. This article will focus on which BPMN2.0 standard elements I used.

Workflow Definition Language (WDL)

Workflow Definition Language (WDL) Workflow Definition Language (WDL) is a Workflow Definition Language.

Following Activiti’s design implementation, WDL is also XML-based.

In the work order system, the author has implemented the following 8 basic elements:


Here are the components of WDL:

The root node consists of two <definitions></definitions> tags:

</definitions> </definitions>Copy the code

2. Process definition nodes, represented by a pair of <process></ Process > tags, form a complete process with their subordinate child nodes.

It is worth mentioning that subProcess is allowed in BPMN2.0 standard, which is not implemented in this work order system.

<process id="verify_work" name=" user audit process "> </process>Copy the code

3. Empty start event node, usually representing the start of a process.

<startEvent id="start" name=" start event "/>Copy the code

4. Timing event definition, which cannot exist alone, has the effect of adding a timer on the basis of other events. Typical application is the timing boundary event mentioned below.

<timerEventDefinition> <timeDuration>${duration}</timeDuration> <! -- Time point or cron expression --> </timerEventDefinition>Copy the code

5. Timed boundary events.

Boundary events are capture events that are attached to a node and listen for the corresponding trigger type while the node is running. When a boundary event is captured, the node interrupts and the subsequent flow of the event is executed.

A timed boundary event can be understood as a clock that pauses to wait for a warning. A timer is started when the process reaches the segment bound to the boundary event.

When the timer is triggered, the link is interrupted and execution continues along the outgoing line of timed boundary events.

<boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="userTask"> <! CancelActivity specifies whether to interrupt the task to which the boundary event is attached. *</timeDuration> </timerEventDefinition> </boundaryEvent>Copy the code

6. Message (boundary) events, where messages are received and sent at a layer of the application or architecture that is embedded in the process engine.

This element is a bit different from the standard. Message events are defined as a means to call back notification in the work order system. Notification types include REST and MQ. The parameters carried by notification can be defined in Params, and name is the parameter name.

The <message> tag is the only sibling of the <process> tag, and message is a global variable that can be referenced by multiple elements in the WDL.

The following defines a message body and refers to it in a message boundary event.

<message id="newInvoice" name="newInvoiceMessage" type="REST | MQ">
   <params>
       <param name="target">${target}</param>
       <param name="a">${a}</param>
       <param name="x">${x}</param>
   </params>
</message>
<boundaryEvent id="boundary" attachedToRef="task" cancelActivity="true">
    <messageEventDefinition messageRef="newInvoice"/>
</boundaryEvent>
Copy the code

The sequential process node, in its representation, is a one-way arrow, so you need to define the elements at both ends. The starting element is defined with the sourceRef attribute, the pointing element is defined with the targetRef attribute, and its value is the id attribute value of the element. As you can see, basic elements on a sequential stream usually need to be identified by an ID attribute, and it is best not to duplicate them to avoid confusion.

<sequenceFlow id="flow1" sourceRef="ss" targetRef="tt" />
Copy the code

8. Conditional flow node, which means that a certain condition is met before the corresponding sequential flow.

<sequenceFlow id="flow1" sourceRef="exclusiveGw" targetRef="task1">
    <conditionExpression>${condition}</conditionExpression>
</sequenceFlow>
Copy the code

9. User task: represents the task node that needs to be operated and promoted by staff.

The BPMN2.0 standard has a wealth of task types such as scripting, Java services, mail, etc. Activiti has expanded to include Mule tasks, Camel tasks, etc.

In the work order system, only user tasks and other events are needed to meet business requirements.

<userTask id="task" name="verify_task"/>
Copy the code

10. An exclusive gateway node, like an if-else determination by a program, connects multiple branches of an exclusive gateway and eventually leads to only one of them.

<exclusiveGateway id="xgid" name="Request approved" default="sf"/> <! -- default indicates the default process -->Copy the code

The parallel gateway node, as opposed to the exclusive gateway node, will have multiple branches connected to the parallel gateway at the same time.

<parallelGateway id="pgid" name="gname"/>
Copy the code

Empty end event node, usually as the end of a process.

<endEvent id="end" name=" end event "/>Copy the code

Supplementary notes:

In the above mentioned timed events, message definitions, sequential flows, and so on, the ${value} form is used in the same way. Instead of using Spring-related parsing methods, it is inspired by Activiti and uses JUEL to parse and execute expressions.

In WDL, complex expressions are not required and simple values and logical operations are supported, for example, ${name}, ${approved==true}.

Ii. Case study

To deepen the understanding of these elements, I selected five representative examples to show the contents of their WDL, illustrated with illustrations from this document.

It is important to note that the children under Definitions are not sequential and do not necessarily follow the path of the WDL. My personal habit is to define the node elements first and then join them using sequential flow.


This case is simpler, with a start node and a task node.

> <process id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" />  <userTask id="unkown" name=""/> <sequenceFlow id="flow1" sourceRef="start" targetRef="unkown"> <conditionExpression>${condition}</conditionExpression> </sequenceFlow> </process> </definitions>Copy the code

This is a typical single-branch sequential process.

<definitions id="def" name=" workflow configuration "> <process id="pid" name="my process"> <startEvent id="start" name=" start" /> <userTask id="write" name="Write monthly financial report"/> <userTask id="verify" name="Verify monthly financial report"/> <sequenceFlow id="flow1" sourceRef="start" targetRef="write"/> <sequenceFlow id="flow2" sourceRef="write" targetRef="verify"/> <sequenceFlow id="flow2" sourceRef="verify" targetRef="end"/> <endEvent id="end"/> </process> </definitions>Copy the code

Here the multi-branching situation occurs and a defaultFlow is defined like this:

if (conditionA) {
    doTask1
} else if (conditionB) {
    doTask3
} else {
    doTask2
}
Copy the code

As you can see, an exclusive gateway is usually accompanied by a defaultFlow. Here’s the WDL.

<definitions id="def" name=" workflow configuration "> <process id="pid" name="my process"> <startEvent id="start" name=" start" /> <userTask id="t1" name="Task1"/> <userTask id="t2" name="Task2"/> <userTask id="t3" name="Task3"/> <exclusiveGateway id="xgid" name="Exclusive Gateway" default="t2"/> <sequenceFlow id="flow1" sourceRef="xgid" targetRef="t1"> <conditionExpression>${conditionA}</conditionExpression> </sequenceFlow> <sequenceFlow id="flow2" sourceRef="xgid" targetRef="t2"/> <sequenceFlow id="flow1" sourceRef="xgid" targetRef="t3"> <conditionExpression>${conditionB}</conditionExpression> </sequenceFlow> </process> </definitions>Copy the code

At this point, you can see a complete process definition, with starts and ends, task nodes, and branches.

> <process id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" />  <userTask id="verifyCreditHistory" name="Verify credit history"/> <sequenceFlow id="verify_flow" sourceRef="start" targetRef="verifyCreditHistory"/> <exclusiveGateway id="approve" name="approve or not"/> <sequenceFlow id="end_flow" sourceRef="verifyCreditHistory" targetRef="approve"> <userTask id="contact" name="Contact customer for further information"/> <sequenceFlow id="disapprove_flow" sourceRef="approve" targetRef="contact"> <conditionExpress>${approve==false}</conditionExpress> </sequenceFlow> <sequenceFlow id="end_flow" sourceRef="contact" targetRef="end1"> <endEvent id="end1"/> <sequenceFlow id="approve_flow" sourceRef="contact" targetRef="end2"> <conditionExpress>${approve==true}</conditionExpress> </sequenceFlow> <endEvent id="end2"/> </process> </definitions>Copy the code

If cancelActivity=”false”, the situation becomes more complicated because there are two terminating nodes. When cancelActivity=”true”, there is only one terminating node.

> <process id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" id="verifyCredit" />  <userTask id="firstLineSupport" name="First line support"/> <boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport"> <timerEventDefinition> <timeDuration>2017-02-12 12:00:00</timeDuration> </timerEventDefinition> </boundaryEvent> <sequenceFlow id="flow1" sourceRef="start" targetRef="firstLineSupport"/> <sequenceFlow id="flow2" sourceRef="firstLineSupport" targetRef="end1"/> <endEvent id="end1"/> <userTask id="secondLineSupport" name="Second line support"/> <sequenceFlow id="flow3" sourceRef="firstLineSupport" targetRef="secondLineSupport"/> <sequenceFlow id="flow4" sourceRef="secondLineSupport" targetRef="end2"/> <endEvent id="end2"/> </process> </definitions>Copy the code

To this, work order system required by the basic knowledge on the end of the explanation. Overall, BPMN2.0 is easy to understand, and can cover the vast majority of work order processes, it can become the industry standard, there are some reasons.