window10
java1.8
mysql8
flowable6
springboot 2.7.6
使用IDEA创建一个SpringBoot项目
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.examplegroupId>
<artifactId>flowable-demoartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>flowable-demoname>
<description>flowable-demodescription>
<properties>
<java.version>1.8java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>2.7.6spring-boot.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.flowablegroupId>
<artifactId>flowable-spring-boot-starterartifactId>
<version>6.4.1version>
<exclusions>
<exclusion>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.2version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.5.3version>
dependency>
<dependency>
<groupId>org.freemarkergroupId>
<artifactId>freemarkerartifactId>
<version>2.3.31version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.1version>
<configuration>
<source>1.8source>
<target>1.8target>
<encoding>UTF-8encoding>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>${spring-boot.version}version>
<configuration>
<mainClass>com.example.flowable.demo.FlowableDemoApplicationmainClass>
<skip>trueskip>
configuration>
<executions>
<execution>
<id>repackageid>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
project>
application.yml中配置
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
spring:
datasource:
url: jdbc:mysql://localhost:3306/flowable_demo?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&allowMultiQueries=true&nullCatalogMeansCurrent=true
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: qk123
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimum-idle: 5
maximum-pool-size: 15
auto-commit: true
idle-timeout: 30000
pool-name: DatebookHikariCP
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
# jackson 配置
jackson:
date-format: yyyy-MM-dd HH:mm:ss
locale: zh
time-zone: GMT+8
#server.servlet.context-path=/
# swagger2使用,不配置这个项目报错 Failed to start bean ‘documentationPluginsBootstrapper‘
flowable:
# 第一次改为true,创建完数据库表结构后,改为false
database-schema-update: true
async-executor-activate: false
server:
port: 11000
# 设置flowable日志级别
logging:
level:
org.flowable: debug
#spring.mvc.pathmatch.matching-strategy=ant-path-matcher
flowable的autoconfig包已经自动配置好了需要的类
直接@Resource就可以使用
部署一个简单流程
import com.example.flowable.demo.controller.vo.DefinitionRequest;
import com.example.flowable.demo.vo.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.impl.bpmn.deployer.ResourceNameUtil;
import org.flowable.engine.repository.DeploymentBuilder;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ModelQuery;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/modeler")
public class ModelerController {
@Resource
private RepositoryService repositoryService;
/**
* 部署流程
* @param definitionRequest
* @return
*/
@PutMapping("/deploy")
public R deployModeler(@RequestBody DefinitionRequest definitionRequest) {
String xmlDefinition = definitionRequest.getXmlDefinition();
DeploymentBuilder deployment = repositoryService.createDeployment();
byte[] bytes = xmlDefinition.getBytes(StandardCharsets.UTF_8);
int i = RandomUtils.nextInt();
String key = "demo_flow_" + i;
String name = "示例流程";
String category = "hello_" + i;
// 流程定义的名称,必须是特定的结尾,否则不会解析
String resourceName = "demo_flow_name_" + i + "." + ResourceNameUtil.BPMN_RESOURCE_SUFFIXES[0];
String id = deployment.addBytes(resourceName, bytes)
.key(key)
.category(category)
.name(name)
.deploy()
.getId();
log.info("部署后id为:{}", id);
Model model = repositoryService.newModel();
model.setDeploymentId(id);
model.setCategory("model_" + category);
model.setKey("model_key_" + i);
model.setName("model_name_" + i);
model.setVersion(1);
repositoryService.saveModel(model);
log.info("模型保存后id:{}", model.getId());
// 设置模型可编辑资源
repositoryService.addModelEditorSource(model.getId(), bytes);
return R.success(id);
}
/**
* 查看流程模型列表
* @return
*/
@GetMapping("/list")
public R list() {
ModelQuery modelQuery = repositoryService.createModelQuery();
List<Model> list = modelQuery.list();
return R.success();
}
}
用postman发送一个请求
{
"xmlDefinition": "\n\n\n \n\n \n \n\n \n \n\n \n \n \n \n \n \n \n \n \n \n \n\n \n \n\n \n \n\n \n \n\n \n\n \n \n\n "
}
import com.example.flowable.demo.controller.vo.DefinitionRequest;
import com.example.flowable.demo.controller.vo.ProcessDefinitionResp;
import com.example.flowable.demo.vo.R;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/process")
public class ProcessController {
@Resource
private RuntimeService runtimeService;
@Resource
private RepositoryService repositoryService;
/**
* 查看流程定义列表
* @return
*/
@GetMapping("/list")
public R list() {
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
List<ProcessDefinition> list = processDefinitionQuery.list();
log.info("得到流程定义数量:{}", list.size());
// ProcessDefinition无法序列化,需要自己转
List<ProcessDefinitionResp> respList = new ArrayList<>();
for (ProcessDefinition processDefinition : list) {
respList.add(ProcessDefinitionResp.copy(processDefinition));
}
return R.success(respList);
}
/**
* 启动流程
* @param definitionRequest
* @return
*/
@PutMapping("/create")
public R create(@RequestBody DefinitionRequest definitionRequest) {
String deploymentId = definitionRequest.getDeploymentId();
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
ProcessDefinition processDefinition = processDefinitionQuery.deploymentId(deploymentId).singleResult();
Map<String, Object> variables = new HashMap<>();
variables.put("employee","张三") ;// 谁申请请假
variables.put("nrOfHolidays",3); // 请几天假
variables.put("description","工作累了,想出去玩玩"); // 请假的原因
ProcessInstance holidayRequest = runtimeService.startProcessInstanceByKey("holidayRequest", variables);
String id = holidayRequest.getId();
log.info("启动的流程实例id:{}, 流程定义id:{}", id, processDefinition.getId());
return R.success(id);
}
}
查看任务
import com.example.flowable.demo.controller.vo.TaskResp;
import com.example.flowable.demo.vo.R;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/task")
public class TaskController {
@Resource
private TaskService taskService;
/**
* 查看所有待办任务
* @return
*/
@GetMapping("/list")
public R list() {
TaskQuery taskQuery = taskService.createTaskQuery();
List<Task> list = taskQuery.list();
List<TaskResp> list1 = new ArrayList<>();
for (Task task : list) {
list1.add(TaskResp.copy(task));
}
return R.success(list1);
}
}
其他类
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Getter
@Setter
@Accessors(chain = true)
public class R implements Serializable {
private int code;
private String message;
private Object data;
public static R gen(int code, String message, Object data) {
return new R().setCode(code).setMessage(message).setData(data);
}
public static R success() {
return R.success(null);
}
public static R success(Object data) {
return R.success("请求成功", data);
}
public static R success(String message, Object data) {
return R.gen(0, message, data);
}
public static R fail() {
return R.fail(null);
}
public static R fail(Object data) {
return R.fail("请求失败", data);
}
public static R fail(String message, Object data) {
return R.gen(-1, message, data);
}
}
import lombok.Getter;
import lombok.Setter;
/**
* 流程定义请求
*/
@Getter
@Setter
public class DefinitionRequest {
// 流程xml定义,部署流程用
private String xmlDefinition;
// 部署id,创建流程用
private String deploymentId;
}
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.flowable.engine.repository.ProcessDefinition;
import java.io.Serializable;
/**
* 流程定义
*/
@Getter
@Setter
@Accessors(chain = true)
public class ProcessDefinitionResp implements Serializable {
String id;
String category;
String name;
String key;
String description;
int version;
String resourceName;
String deploymentId;
String diagramResourceName;
boolean hasStartFormKey;
boolean hasGraphicalNotation;
boolean suspended;
String tenantId;
String derivedFrom;
String derivedFromRoot;
int derivedVersion;
String engineVersion;
public static ProcessDefinitionResp copy(ProcessDefinition processDefinition) {
ProcessDefinitionResp definitionResp = new ProcessDefinitionResp();
definitionResp.setId(processDefinition.getId());
definitionResp.setCategory(processDefinition.getCategory());
definitionResp.setName(processDefinition.getName());
definitionResp.setKey(processDefinition.getKey());
definitionResp.setDescription(processDefinition.getDescription());
definitionResp.setVersion(processDefinition.getVersion());
definitionResp.setResourceName(processDefinition.getResourceName());
definitionResp.setDeploymentId(processDefinition.getDeploymentId());
definitionResp.setDiagramResourceName(processDefinition.getDiagramResourceName());
definitionResp.setHasStartFormKey(processDefinition.hasStartFormKey());
definitionResp.setHasGraphicalNotation(processDefinition.hasGraphicalNotation());
definitionResp.setSuspended(processDefinition.isSuspended());
definitionResp.setTenantId(processDefinition.getTenantId());
definitionResp.setDerivedFrom(processDefinition.getDerivedFrom());
definitionResp.setDerivedFromRoot(processDefinition.getDerivedFromRoot());
definitionResp.setDerivedVersion(processDefinition.getDerivedVersion());
definitionResp.setEngineVersion(processDefinition.getEngineVersion());
return definitionResp;
}
}
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.flowable.task.api.Task;
import java.io.Serializable;
import java.util.*;
/**
* 任务
*/
@Getter
@Setter
@Accessors(chain = true)
public class TaskResp implements Serializable {
String id;
String name;
String description;
int priority;
String owner;
String assignee;
String processInstanceId;
String executionId;
String taskDefinitionId;
String processDefinitionId;
String scopeId;
String subScopeId;
String scopeType;
String scopeDefinitionId;
Date createTime;
String taskDefinitionKey;
Date dueDate;
String category;
String parentTaskId;
String tenantId;
String formKey;
Map<String, Object> taskLocalVariables;
Map<String, Object> processVariables;
List<IdentityLinkInfoResp> identityLinks;
Date claimTime;
public static TaskResp copy(Task task) {
TaskResp taskResp = new TaskResp();
taskResp.setId(task.getId());
taskResp.setName(task.getName());
taskResp.setDescription(task.getDescription());
taskResp.setPriority(task.getPriority());
taskResp.setOwner(task.getOwner());
taskResp.setAssignee(task.getAssignee());
taskResp.setProcessInstanceId(task.getProcessInstanceId());
taskResp.setExecutionId(task.getExecutionId());
taskResp.setTaskDefinitionId(task.getTaskDefinitionId());
taskResp.setProcessDefinitionId(task.getProcessDefinitionId());
taskResp.setScopeId(task.getScopeId());
taskResp.setSubScopeId(task.getSubScopeId());
taskResp.setScopeType(task.getScopeType());
taskResp.setScopeDefinitionId(task.getScopeDefinitionId());
taskResp.setCreateTime(task.getCreateTime());
taskResp.setTaskDefinitionKey(task.getTaskDefinitionKey());
taskResp.setDueDate(task.getDueDate());
taskResp.setCategory(task.getCategory());
taskResp.setParentTaskId(task.getParentTaskId());
taskResp.setTenantId(task.getTenantId());
taskResp.setFormKey(task.getFormKey());
taskResp.setTaskLocalVariables(task.getTaskLocalVariables());
taskResp.setProcessVariables(task.getProcessVariables());
// List extends IdentityLinkInfo> identityLinks1 = task.getIdentityLinks();
taskResp.setIdentityLinks(new ArrayList<>());
// if (Objects.nonNull(identityLinks1) && !identityLinks1.isEmpty()) {
// for (IdentityLinkInfo identityLinkInfo : identityLinks1) {
// taskResp.getIdentityLinks().add(IdentityLinkInfoResp.copy(identityLinkInfo));
// }
// }
taskResp.setClaimTime(task.getClaimTime());
return taskResp;
}
}
Modeler 模型
Process 流程
Task 任务
模型部署后,就是流程定义。
从流程定义创建流程实例。
流程实例中有多个任务,任务有很多种类。