workflow之sdk-java
一、workflow是什么?
workflow是为了完成一些预定的目的,根据一组规则,而制定的一系列步骤。对于一个开发者来说,workflow则是将复杂的业务规则以及控制流程以图形化的方法声明出来,组成一个高度可视化的图形环境。(来自百度百科 https://blog.csdn.net/scwulian/article/details/20543049)
二、sdk-java
https://github.com/serverlessworkflow/sdk-java
SDK Version | JDK Version |
---|---|
5.0.0 and after | 11 |
4.0.x and before | 8 |
build projects:
To build project and run tests locally:
git clone https://github.com/serverlessworkflow/sdk-java.git
mvn clean install
Maven projects:
a) Add the following repository to your pom.xml section:repositories
<repository>
<id>oss.sonatype.org-snapshot</id>
<url>http://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
b) Add the following dependencies to your pom.xml section:dependencies
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-api</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-spi</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-validation</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-diagram</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.serverlessworkflow</groupId>
<artifactId>serverlessworkflow-util</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
这里使用的是5.0的依赖,所以JDK要11及以上
三、How to Use
You can create a Workflow instance from JSON/YAML source:
Let's say you have a simple YAML based workflow definition:
我们准备一个yaml文件, test.yaml, 放到resources目录下
id: greeting
version: '1.0'
name: Greeting Workflow
start: Greet
description: Greet Someone
functions:
- name: greetingFunction
operation: file://myapis/greetingapis.json#greeting
states:
- name: Greet
type: operation
actions:
- functionRef:
refName: greetingFunction
arguments:
name: "${ .greet.name }"
actionDataFilter:
results: "${ .payload.greeting }"
stateDataFilter:
output: "${ .greeting }"
end: true
准备个 WorkFlowerTest.java
package com.liufei.demo;
import io.serverlessworkflow.api.Workflow;
import io.serverlessworkflow.api.interfaces.State;
import io.serverlessworkflow.api.interfaces.WorkflowDiagram;
import io.serverlessworkflow.diagram.WorkflowDiagramImpl;
import io.serverlessworkflow.utils.WorkflowUtils;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
public class WorkFlowerTest {
@Test
public void test() throws IOException {
ClassPathResource classPathResource = new ClassPathResource("test.yaml");
InputStream inputStream = classPathResource.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
String source = readFileAsString(inputStreamReader);
try {
Workflow workflow = Workflow.fromSource(source);
WorkflowDiagram workflowDiagram = new WorkflowDiagramImpl();
workflowDiagram.setWorkflow(workflow).showLegend(true);
String diagramSVG = workflowDiagram.getSvgDiagram();
System.out.println("结果:" + diagramSVG);
State startingState = WorkflowUtils.getStartingState(workflow);
System.out.println("状态:" + startingState.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
public String readFileAsString(Reader reader) {
try {
StringBuilder fileData = new StringBuilder(1000);
char[] buf = new char[1024];
int numRead;
while ((numRead = reader.read(buf)) != -1) {
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1024];
}
reader.close();
return fileData.toString();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
结果返回的是个svg文件的内容:
点击查看SVG内容
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="297px" preserveAspectRatio="none" style="width:491px;height:297px;background:#000000;" version="1.1" viewBox="0 0 491 297" width="491px" zoomAndPan="magnify"><defs/><g><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="140" x="120.5" y="19.5332">Dot Executable: null</text><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="173" x="120.5" y="37.1426">No dot executable found</text><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="258" x="120.5" y="54.752">Cannot find Graphviz. You should try</text><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="0" x="124.5" y="72.3613"/><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="71" x="120.5" y="89.9707">@startuml</text><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="50" x="120.5" y="107.5801">testdot</text><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="66" x="120.5" y="125.1895">@enduml</text><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="0" x="124.5" y="142.7988"/><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="15" x="124.5" y="160.4082">or</text><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="0" x="124.5" y="178.0176"/><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="201" x="120.5" y="195.627">java -jar plantuml.jar -testdot</text><text fill="#33FF02" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="0" x="124.5" y="213.2363"/><rect fill="#FFFFFF" height="66.8281" rx="5" ry="5" style="stroke: #FFFFFF; stroke-width: 1.0;" width="482" x="8" y="229.3125"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="200" x="14" y="248.8457">State Types and Border Colors:</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="41" x="18" y="268.4551">Event</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="70" x="67" y="268.4551">Operation</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="46" x="145" y="268.4551">Switch</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="40" x="199" y="268.4551">Sleep</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="52" x="247" y="268.4551">Parallel</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="39" x="307" y="268.4551">Inject</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="58" x="354" y="268.4551">ForEach</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="60" x="420" y="268.4551">CallBack</text><rect fill="#7FE5F0" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="49" x="14" y="271.5313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="18" y="286.0645"/><rect fill="#BADA55" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="78" x="63" y="271.5313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="67" y="286.0645"/><rect fill="#92A0F2" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="54" x="141" y="271.5313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="145" y="286.0645"/><rect fill="#B83B5E" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="48" x="195" y="271.5313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="199" y="286.0645"/><rect fill="#6A2C70" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="60" x="243" y="271.5313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="247" y="286.0645"/><rect fill="#1E5F74" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="47" x="303" y="271.5313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="307" y="286.0645"/><rect fill="#931A25" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="66" x="350" y="271.5313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="354" y="286.0645"/><rect fill="#FFCB8E" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="68" x="416" y="271.5313"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="420" y="286.0645"/><line style="stroke: #000000; stroke-width: 1.0;" x1="14" x2="484" y1="253.9219" y2="253.9219"/><line style="stroke: #000000; stroke-width: 1.0;" x1="14" x2="484" y1="271.5313" y2="271.5313"/><line style="stroke: #000000; stroke-width: 1.0;" x1="14" x2="484" y1="289.1406" y2="289.1406"/><line style="stroke: #000000; stroke-width: 1.0;" x1="14" x2="14" y1="253.9219" y2="289.1406"/><line style="stroke: #000000; stroke-width: 1.0;" x1="63" x2="63" y1="253.9219" y2="289.1406"/><line style="stroke: #000000; stroke-width: 1.0;" x1="141" x2="141" y1="253.9219" y2="289.1406"/><line style="stroke: #000000; stroke-width: 1.0;" x1="195" x2="195" y1="253.9219" y2="289.1406"/><line style="stroke: #000000; stroke-width: 1.0;" x1="243" x2="243" y1="253.9219" y2="289.1406"/><line style="stroke: #000000; stroke-width: 1.0;" x1="303" x2="303" y1="253.9219" y2="289.1406"/><line style="stroke: #000000; stroke-width: 1.0;" x1="350" x2="350" y1="253.9219" y2="289.1406"/><line style="stroke: #000000; stroke-width: 1.0;" x1="416" x2="416" y1="253.9219" y2="289.1406"/><line style="stroke: #000000; stroke-width: 1.0;" x1="484" x2="484" y1="253.9219" y2="289.1406"/></g></svg>
我们创建一个test.svg文件,然后将内容copy过去,使用浏览器打开
这个意思是说电脑上没有安装 Graphviz。所以生成的svg文件内容不完整。
手动安装下:
https://graphviz.org/download/
安装完成之后,打开cmd开下版本:dot -version
然后再重新运行下上面的java程序。重新生成svg内容
点击查看SVG内容
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="344px" preserveAspectRatio="none" style="width:491px;height:344px;" version="1.1" viewBox="0 0 491 344" width="491px" zoomAndPan="magnify"><defs><filter height="300%" id="f3qejnd" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><rect fill="#FFFFFF" filter="url(#f3qejnd)" height="250.6094" rx="12.5" ry="12.5" style="stroke: #000000; stroke-width: 1.5;" width="196" x="145.5" y="8"/><rect fill="#FFFFFF" height="217" rx="12.5" ry="12.5" style="stroke: #FFFFFF; stroke-width: 1.0;" width="190" x="148.5" y="38.6094"/><line style="stroke: #000000; stroke-width: 1.5;" x1="145.5" x2="341.5" y1="35.6094" y2="35.6094"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="147" x="170" y="27.5332">Greeting Workflow v1.0</text><rect fill="#F8F8FF" filter="url(#f3qejnd)" height="82.8906" rx="12.5" ry="12.5" style="stroke: #BADA55; stroke-width: 1.5;" width="152" x="156.5" y="104.6094"/><line style="stroke: #BADA55; stroke-width: 1.5;" x1="156.5" x2="308.5" y1="132.2188" y2="132.2188"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="36" x="214.5" y="124.1426">Greet</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="117" x="161.5" y="149.6758">Type: Operation State</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="132" x="161.5" y="164.7695">Action mode: sequential</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="99" x="161.5" y="179.8633">Num. of actions: 1</text><ellipse cx="232.5" cy="58.6094" fill="#008000" filter="url(#f3qejnd)" rx="10" ry="10" style="stroke: none; stroke-width: 1.0;"/><ellipse cx="232.5" cy="233.6094" fill="none" filter="url(#f3qejnd)" rx="10" ry="10" style="stroke: #FFA500; stroke-width: 1.0;"/><ellipse cx="233" cy="234.1094" fill="#FFA500" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><path d="M232.5,68.7594 C232.5,76.3694 232.5,87.8294 232.5,99.5694 " fill="none" style="stroke: #000000; stroke-width: 1.0;"/><polygon fill="#000000" points="232.5,104.6094,236.5,95.6094,232.5,99.6094,228.5,95.6094,232.5,104.6094" style="stroke: #000000; stroke-width: 1.0;"/><path d="M232.5,187.8594 C232.5,198.7594 232.5,209.8394 232.5,218.2394 " fill="none" style="stroke: #000000; stroke-width: 1.0;"/><polygon fill="#000000" points="232.5,223.5994,236.5,214.5994,232.5,218.5994,228.5,214.5994,232.5,223.5994" style="stroke: #000000; stroke-width: 1.0;"/><rect fill="#FFFFFF" height="66.8281" rx="5" ry="5" style="stroke: #FFFFFF; stroke-width: 1.0;" width="482" x="8" y="277"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="200" x="14" y="296.5332">State Types and Border Colors:</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="41" x="18" y="316.1426">Event</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="70" x="67" y="316.1426">Operation</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="46" x="145" y="316.1426">Switch</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="40" x="199" y="316.1426">Sleep</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="52" x="247" y="316.1426">Parallel</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="39" x="307" y="316.1426">Inject</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="58" x="354" y="316.1426">ForEach</text><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="60" x="420" y="316.1426">CallBack</text><rect fill="#7FE5F0" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="49" x="14" y="319.2188"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="18" y="333.752"/><rect fill="#BADA55" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="78" x="63" y="319.2188"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="67" y="333.752"/><rect fill="#92A0F2" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="54" x="141" y="319.2188"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="145" y="333.752"/><rect fill="#B83B5E" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="48" x="195" y="319.2188"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="199" y="333.752"/><rect fill="#6A2C70" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="60" x="243" y="319.2188"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="247" y="333.752"/><rect fill="#1E5F74" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="47" x="303" y="319.2188"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="307" y="333.752"/><rect fill="#931A25" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="66" x="350" y="319.2188"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="354" y="333.752"/><rect fill="#FFCB8E" height="17.6094" style="stroke: none; stroke-width: 1.0;" width="68" x="416" y="319.2188"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="0" x="420" y="333.752"/><line style="stroke: #000000; stroke-width: 1.0;" x1="14" x2="484" y1="301.6094" y2="301.6094"/><line style="stroke: #000000; stroke-width: 1.0;" x1="14" x2="484" y1="319.2188" y2="319.2188"/><line style="stroke: #000000; stroke-width: 1.0;" x1="14" x2="484" y1="336.8281" y2="336.8281"/><line style="stroke: #000000; stroke-width: 1.0;" x1="14" x2="14" y1="301.6094" y2="336.8281"/><line style="stroke: #000000; stroke-width: 1.0;" x1="63" x2="63" y1="301.6094" y2="336.8281"/><line style="stroke: #000000; stroke-width: 1.0;" x1="141" x2="141" y1="301.6094" y2="336.8281"/><line style="stroke: #000000; stroke-width: 1.0;" x1="195" x2="195" y1="301.6094" y2="336.8281"/><line style="stroke: #000000; stroke-width: 1.0;" x1="243" x2="243" y1="301.6094" y2="336.8281"/><line style="stroke: #000000; stroke-width: 1.0;" x1="303" x2="303" y1="301.6094" y2="336.8281"/><line style="stroke: #000000; stroke-width: 1.0;" x1="350" x2="350" y1="301.6094" y2="336.8281"/><line style="stroke: #000000; stroke-width: 1.0;" x1="416" x2="416" y1="301.6094" y2="336.8281"/><line style="stroke: #000000; stroke-width: 1.0;" x1="484" x2="484" y1="301.6094" y2="336.8281"/></g></svg>
可以看到一个流程图就出来了。
四、其他语言
https://github.com/serverlessworkflow/specification
五:相关资料
PlantUML简述: https://plantuml.com/zh/