准备工作
引入依赖 flowable-spring-boot-starter
个人用的6.7.0版本的flowable
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
application.yaml配置
flowable:
#关闭定时任务JOB
async-executor-activate: false
# 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
database-schema-update: true
# datasource configuration is required
spring.datasource:
url: jdbc:mysql://localhost:3306/flowable?useUnicode=true&characterEncoding=utf8&nullCatalogMeansCurrent=true&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
绘制流程图
这个我没自己部署,找了别人在云服务器搭建好的画的,随便的,没啥逻辑,
关于流程图的绘画传参及表达式的使用,下篇文章说明。
画好流程图后点击下载,可导出 bpmn20.xml结尾的文件
部署流程
集成springboot的flowable可以自动部署,也可以选择手动部署
项目启动时会自动部署resources下的bpmn文件
手动部署
我写了一个上传文件部署的接口
package com.example.demo.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
@Api
@RestController
public class DeployProcess {
@Autowired
private RepositoryService repositoryService;
@ApiOperation(value = "部署流程")
@PostMapping("/deployProcess")
public void deployProcess(MultipartFile file){
String name =file.getOriginalFilename();
try {
InputStream inputStream = file.getInputStream();
Deployment deployment = repositoryService.createDeployment()
//部署名
.name("ManualDeployment")
//resourceName,即文件名,一定要以BPMN或者BPMN20.xml结尾不然部署时不会插入act_re_procedf表,无法获取到流程
.addInputStream(name,inputStream)
.deploy();
} catch (IOException e) {
e.printStackTrace();
}
}
}
开启流程实例
runtimeService.startProcessInstanceByKey()
@ApiOperation(value = "报销申请")
@PostMapping("/start/{userId}/{amount}")
public String startApply(@PathVariable String userId, @PathVariable String amount) {
HashMap<String, Object> map = new HashMap<>();
map.put("userId", userId);
map.put("amount", amount);
ProcessInstance instance =
runtimeService.startProcessInstanceByKey("reimbursement", map);
if (instance == null) {
return null;
}else {
return instance.getProcessInstanceId();
}
}
start的key为流程的Id,
查询待办任务
taskService.createTaskQuery()
@ApiOperation(value = "获取需要审核的项目申请列表")
@GetMapping(value = "/project/approve/list")
public @ResponseBody
List<ReimbursementRecord> getAllParticipateRequest(String employee,String department, String auditLevel) {
//get the taskList
List<Task> tasks;
if (StringUtils.isNotBlank(employee)) {
//按候选人查询
tasks = taskService.createTaskQuery().
taskName(auditLevel).taskAssignee(employee).
// taskCandidateOrAssigned(employee).
list();
}else {
//按候选组查询
tasks = taskService.createTaskQuery().
taskName(auditLevel).
taskCandidateGroup(department).
list();
}
List<ReimbursementRecord> records = new ArrayList<ReimbursementRecord>(tasks.size());
tasks.forEach( task -> {
ReimbursementRecord record = new ReimbursementRecord();
String taskId = task.getId();
Map<String, Object> variables = taskService.getVariables(taskId);
String userId = (String)variables.get("userId") ;
String amount = (String) variables.get("amount");
record.setUserId(userId);
record.setAmount(amount);
record.setTaskId(taskId);
records.add(record);
});
return records;
}
完成任务
taskService.complete();
@ApiOperation(value = "审核项目申请")
@PostMapping(value = "/participateRequests/{taskId}")
public boolean approveParticipateRequest(@PathVariable String taskId, boolean passed, String employee,String department) {
Task task ;
if("财务".equals(department)){
task = taskService.createTaskQuery().taskAssignee(employee).taskId(taskId).singleResult();
}else {
task = taskService.createTaskQuery().taskCandidateGroup(department).taskId(taskId).singleResult();
}
if (task == null) {
LOGGER.error("The task not found, task id is {}", taskId);
return false;
}else {
//business logic here
//Into next step
LOGGER.info("The taskId is {}", taskId);
Map<String, Object> variables = new HashMap<>();
variables.put("approved", passed);
taskService.complete(task.getId(), variables);
return true;
}
}
查看运行中的流程图
这个我也是网上找来的,需要注意的是diagramGenerator.generateDiagram()方法在 从6.4版本开始增加了drawSequenceFlowNameWithNoLabelDI(是否显示连接线名称)这个参数,drawSequenceFlowNameWithNoLabelDI默认是false,如果你的连线名称不显示,记得设置这个属性为true就好了。6.4以前的版本有这个bug无法显示连接线名称。
@RequestMapping(value = "processDiagram")
public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
//流程走完的不显示图
if (pi == null) {
return;
}
Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
//使用流程实例ID,查询正在执行的执行对象表,返回流程实例对象
String InstanceId = task.getProcessInstanceId();
List<Execution> executions = runtimeService
.createExecutionQuery()
.processInstanceId(InstanceId)
.list();
//得到正在执行的Activity的Id
List<String> activityIds = new ArrayList<>();
List<String> flows = new ArrayList<>();
for (Execution exe : executions) {
List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
activityIds.addAll(ids);
}
//获取流程图
BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0,true);
OutputStream out = null;
byte[] buf = new byte[1024];
int legth = 0;
try {
out = httpServletResponse.getOutputStream();
while ((legth = in.read(buf)) != -1) {
out.write(buf, 0, legth);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}