后端FlowableFlowable-HelloWorld
cmyang简介
轻量级工作流引擎,使用Java编写,Flowable是Activiti的fork
github地址:https://github.com/flowable/flowable-engine
开源文档:https://wwv.flowable.com/open-source/docs/bpmn/ch02-GettingStarted/
6.5.0版本中文文档:https://jeesite.gitee.io/front/flowable/6.5.0/bpmn/index.html
Hello World
Gitee地址:https://gitee.com/aacopy/flowable-learn.git
创建一个spring boot项目
需要加入 spring web,
本示例,spring boot 2.6.1,flowable 6.7.1, mysql 5.7
创建数据库
新建一个mysql数据库,名称为flowable_learn
编写示例
- 加入maven依赖
1 2 3 4 5 6 7 8 9
| <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>6.7.1</version> </dependency>
|
- 在application.properties新增配置项
1 2 3 4 5
| server.servlet.context-path=/flowable-learn
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable_learn?characterEncoding=UTF-8 spring.datasource.username=root spring.datasource.password=123456
|
此处有坑:
如果启动服务,报错找不到flowable的表
原因:使用root用户登录,程序检测到该用户下的其他数据库中有flowable相关的表,就不再创建表了,但是在使用的时候又找不到表。
解决:在url后面追加&nullCatalogMeansCurrent=true
1
| spring.datasource.url=jdbc:mysql://127.0.0.1:3306/flowable_learn?characterEncoding=UTF-8&nullCatalogMeansCurrent=true
|
- 在resources文件夹下新建文件夹processes
- 创建一个流程文件hello-world.bpmn20.xml,复制以下内容到文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.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://flowable.org/test" exporter="Flowable Open Source Modeler" exporterVersion="1.1.0-SNAPSHOT"> <process id="helloWorldProcess" name="Hello World Process"> <startEvent id="theStart" /> <sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" /> <userTask id="theTask" name="my task" flowable:assignee="aacopy" /> <sequenceFlow id="flow2" sourceRef="theTask" targetRef="theEnd" /> <endEvent id="theEnd" /> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_helloWorldProcess"> <bpmndi:BPMNPlane id="BPMNPlane_helloWorldProcess" bpmnElement="helloWorldProcess"> <bpmndi:BPMNEdge id="flow1_di" bpmnElement="flow1"> <omgdi:waypoint x="130" y="178" /> <omgdi:waypoint x="180" y="178" /> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge id="flow2_di" bpmnElement="flow2"> <omgdi:waypoint x="280" y="178" /> <omgdi:waypoint x="332" y="178" /> </bpmndi:BPMNEdge> <bpmndi:BPMNShape id="BPMNShape_theStart" bpmnElement="theStart"> <omgdc:Bounds x="100" y="163" width="30" height="30" /> </bpmndi:BPMNShape> <bpmndi:BPMNShape id="theTask_di" bpmnElement="theTask"> <omgdc:Bounds x="180" y="138" width="100" height="80" /> </bpmndi:BPMNShape> <bpmndi:BPMNShape id="theEnd_di" bpmnElement="theEnd"> <omgdc:Bounds x="332" y="160" width="36" height="36" /> </bpmndi:BPMNShape> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>
|
- 编写HelloWorldController类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| package cn.aacopy.learn.flowable;
import org.flowable.common.engine.impl.util.IoUtil; import org.flowable.engine.RepositoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.task.api.Task; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors;
@RestController @RequestMapping("/helloWorld") public class HelloWorldController {
@Autowired private RuntimeService runtimeService;
@Autowired private TaskService taskService;
@Autowired private RepositoryService repositoryService;
@RequestMapping("/image") public void image(HttpServletResponse response) throws IOException { ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionKey("helloWorldProcess").latestVersion().singleResult(); InputStream imageStream = repositoryService.getProcessDiagram(processDefinition.getId()); byte[] data = IoUtil.readInputStream(imageStream, "image inputStream name"); response.setContentType(MediaType.IMAGE_PNG_VALUE); response.getOutputStream().write(data); }
@RequestMapping("/start") public String start() { runtimeService.startProcessInstanceByKey("helloWorldProcess"); return "success"; }
@RequestMapping("/todo") public List<Map<String, Object>> todo(String assignee) { List<Task> list = taskService.createTaskQuery() .taskAssignee(assignee).orderByTaskCreateTime().desc().list(); return list.stream().map(task -> { Map<String, Object> taskMap = new HashMap<>(); taskMap.put("id", task.getId()); taskMap.put("name", task.getName()); taskMap.put("createTime", task.getCreateTime()); return taskMap; }).collect(Collectors.toList()); }
@RequestMapping("/complete") public String complete(String taskId) { taskService.complete(taskId); return "success"; } }
|
运行示例
第一次启动,程序会自动创建flowable相关表,启动需要的时间较长
打开浏览器测试
- 查看流程图
http://127.0.0.1:8080/flowable-learn/helloWorld/image
- 启动流程
http://127.0.0.1:8080/flowable-learn/helloWorld/start
- 查看待办任务
http://127.0.0.1:8080/flowable-learn/helloWorld/todo?assignee=aacopy
1
| [{"createTime":"2021-12-02T08:57:27.886+00:00","name":"my task","id":"e0193bb3-534d-11ec-ac8c-d08e7902fe33"}]
|
- 提交任务
taskId入参填写“查看待办任务”接口返回列表中的id值
http://127.0.0.1:8080/flowable-learn/helloWorld/complete?taskId=e0193bb3-534d-11ec-ac8c-d08e7902fe33