springboot整合flowable框架入门步骤

网友投稿 461 2022-08-14


springboot整合flowable框架入门步骤

最近工作中有用到工作流的开发,引入了flowable工作流框架,在此记录一下springboot整合flowable工作流框架的过程,以便后续再次使用到时可以做一些参考使用,如果项目中有涉及到流程审批的话,可以使用该框架帮我们实现流程图示化展示的功能,为了快速了解flowable工作流框架的一个使用过程,我们直接步入主题,springboot整合flowable工作流框架的步骤如下:

1、首先创建一个springboot工程,然后引入flowable pom依赖,代码如下:

org.flowable

flowable-spring-boot-starter

6.7.0

2、创建流程图定义文档

这里有一个使用flowable-ui可视化的工程来创建流程图定义文档,https://wandouip.com/t5i212543/,具体实施过程如下:

先从 https://github.com/flowable/flowable-engine/releases 上下载一个发布文档,这里选择Flowable 6.7.2 release;然后解压缩文件,将里面的wars文档下的两个jar包(flowable-rest.war、flowable-ui.war)部署到tomcat下,放到webapps文件加下,点击运行,运行存在一个解压缩文件的过程,会产生flowable-rest、flowable-ui文件夹,浏览器输入 http://localhost:8080/flowable-ui,如下图:

用户名密码输入admin/test,如下图:

点击建模器应用程序,点击右上角”创建流程“,填写相关信息,进去后就可以可视化地创建流程,如下图:

上面初步展示了使用可视化制作工具制作流程图的过程,然后导出BPMN2文件,文件内容大概如下:

以上初步实现怎么使用可视化工具来创建流程图定义文件,里面更为具体的使用方法还有待探索,上面的步骤执行完毕后,我们就可以运行我们的springboot工程了,在配置文件中配置好数据库链接相关的信息后,然后配置flowable相关信息:

flowable:  aysnc-executor-activate: false  database-schema-update: true  process-definition-location-prefix: classpath*:/processes/  process-definition-location-suffixes: "**.bpmn20.xml, **.bpmn"

上面的信息配置完毕后,就可以运行我们的工程了,在运行工程之前,在工程的resources文件夹下创建一个processes文件夹,我们的流程定义文档就放在这个文件夹下,创建一个process-test.bpmn20.xml放到processes文件夹下,具体内容定义如下:

xmlns="http://omg.org/spec/BPMN/20100524/MODEL"

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://w3.org/2001/XMLSchema"

xmlns:activiti="http://activiti.org/bpmn"

xmlns:bpmndi="http://omg.org/spec/BPMN/20100524/DI"

xmlns:omgdc="http://omg.org/spec/DD/20100524/DC"

xmlns:omgdi="http://omg.org/spec/DD/20100524/DI"

typeLanguage="http://w3.org/2001/XMLSchema"

expressionLanguage="http://w3.org/1999/XPath"

targetNamespace="http://activiti.org/test">

activiti:class="com.chinaums.web.controller.flowable2.delegate.SendJuniorRejectionMailDelegate">

<![CDATA[${approved=='Y'}]]>

<![CDATA[${approved=='N'}]]>

<![CDATA[${approved=='Y'}]]>

activiti:class="com.chinaums.web.controller.flowable2.delegate.SendSeniorRejectionMailDelegate">

<![CDATA[${approved=='N'}]]>

activiti:class="com.chinaums.web.controller.flowable2.delegate.SendApprovalSuccessEmailDelegate">

sourceRef="sendApprovalSuccessEmail"

targetRef="approvalSuccessEnd">

xmlns="http://omg.org/spec/BPMN/20100524/MODEL"

xmlns:xsi="http://w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://w3.org/2001/XMLSchema"

xmlns:activiti="http://activiti.org/bpmn"

xmlns:bpmndi="http://omg.org/spec/BPMN/20100524/DI"

xmlns:omgdc="http://omg.org/spec/DD/20100524/DC"

xmlns:omgdi="http://omg.org/spec/DD/20100524/DI"

typeLanguage="http://w3.org/2001/XMLSchema"

expressionLanguage="http://w3.org/1999/XPath"

targetNamespace="http://activiti.org/test">

activiti:class="com.chinaums.web.controller.flowable2.delegate.SendJuniorRejectionMailDelegate">

activiti:class="com.chinaums.web.controller.flowable2.delegate.SendJuniorRejectionMailDelegate">

<![CDATA[${approved=='Y'}]]>

<![CDATA[${approved=='N'}]]>

<![CDATA[${approved=='Y'}]]>

activiti:class="com.chinaums.web.controller.flowable2.delegate.SendSeniorRejectionMailDelegate">

activiti:class="com.chinaums.web.controller.flowable2.delegate.SendSeniorRejectionMailDelegate">

<![CDATA[${approved=='N'}]]>

activiti:class="com.chinaums.web.controller.flowable2.delegate.SendApprovalSuccessEmailDelegate">

activiti:class="com.chinaums.web.controller.flowable2.delegate.SendApprovalSuccessEmailDelegate">

sourceRef="sendApprovalSuccessEmail"

targetRef="approvalSuccessEnd">

sourceRef="sendApprovalSuccessEmail"

targetRef="approvalSuccessEnd">

上面文件中的process标签的id值是该流程定义的唯一标识,在创建流程实例时需要传入processId标识,上面的assignee变量后面定义了一个变量${seniorAdmin},这个是由接口调用时传入的,activiti:class后面的值是一个类,表示执行到这个步骤时会触发执行某个动作,比如id为sendJuniorRectEmail的serviceTask中的class定义如下:

@Slf4j

public class SendJuniorRejectionMailDelegate implements javaDelegate {

@Override

public void execute(DelegateExecution execution) {

String requestUser = (String) execution.getVariable("requestUser");

String resourceId = (String) execution.getVariable("resourceId");

System.out.println("SendJuniorRejectionMailDelegate");

log.info("send approval success mail for user [" + requestUser + "] with apply resource [" + resourceId + "]");

}

}

上面的类需要实现JavaDelegate这个接口,上面的内容定义完毕后,就可以定义我们的实现方法了,先创建一个接口,定义一些方法:

public interface IProcess {

/**

* 创建一个流程实例,创建实例时会登记一些信息,这些信息可以通过调用

* queryProcessVariables方法获取到,调用时需要传递processInstanceId

* @param paramObj

* @return

*/

ProcessInstanceEntity startProcess(ParamObj paramObj);

/**

* 获取指定工作人的代办任务

* @param assignee

* @return

*/

List taskInstance(String assignee);

/**

* 处理工作

* @param paramObj

*/

void handleTask(ParamObj paramObj);

/**

* 获取某个流程实体的状态,各个审批环节所处的状态信息

* @param processInstanceId

* @return

*/

List queryProcessStatus(String processInstanceId);

/**

* 查看创建流程实例时登记的变量信息

* @param processInstanceId

* @return

*/

Map queryProcessVariables(String processInstanceId);

/**

* 获取某人的历史审批数据

* @param assignee

* @return

*/

List queryHistoryProcess(String assignee);

/**

* 生成流程的图谱

* @param httpServletResponse

* @param processInstanceId

*/

void genProcessDiagram(HttpServletResponse httpServletResponse, String processInstanceId) throws Exception;

/**

* 查询是否存在历史数据的流程实例

* @param processInstanceId

* @return

*/

boolean isExistHistoricProcessInstance(String processInstanceId);

/**

* 查询指定的流程是否是运行中的流程

* @param processInstanceId

* @return

*/

boolean isExistRunningProcessInstance(String processInstanceId);

/**

* 将指定的流程挂起

* @param processInstanceId

*/

void suspendProcessInstance(String processInstanceId);

/**

* 终止项目流程

* @param paramObj

*/

void terminateProcessInstance(ParamObj paramObj);

/**

* 将指定的流程激活

* @param processInstanceId

*/

void activateProcessInstance(String processInstanceId);

/**

* 删除流程实例

* @param paramObj

*/

void deleteProcessInstance(ParamObj paramObj);

/**

* 将任务返回到某一步骤

* @param taskId

* @param targetTaskKey 返回到的目标任务ID

*/

void rollbackTask(String taskId, String targetTaskKey);

boolean isProcessFinished(String processInstanceId);

}

定义好接口后,再定义一个实现类:

@Service

public class IProcessImpl implements IProcess {

@Autowired

private RepositoryService repositoryService;

private RuntimeService runtimeService;

private TaskService taskService;

private HistoryService historyService;

private ProcessEngine processEngine;

ManagementService managementService;

@Override

public ProcessInstanceEntity startProcess(ParamObj paramObj) {

Map variables = new HashMap<>();

// 请求的资源ID

variables.put("resourceId", paramObj.getResourceId());

// 请求发起用户

variables.put("requestUser", paramObj.getRequestUser());

// 初级审批用户

variables.put("juniorAdmin", paramObj.getJuniorAdmin());

// 高级审批用户

variables.put("seniorAdmin", paramObj.getSeniorAdmin());

ProcessInstance processInstance=runtimeService.

startProcessInstanceByKey(ConstantValues.FLOWABLE_PROCESS_TEST, variables);

ProcessInstanceEntity entity=new ProcessInstanceEntity();

entity.setProcessDeploymentId(processInstance.getDeploymentId());

entity.setProcessInstanceId(processInstance.getProcessInstanceId());

entity.setActivityId(processInstance.getActivityId());

return entity;

}

public List taskInstance(String assignee) {

List entities=new ArrayList<>();

List tasks= taskService.createTaskQuery().taskAssignee(assignee).orderByTaskCreateTime().desc().list();

if(!CollectionUtils.isEmpty(tasks)){

tasks.stream().forEach(task -> {

TaskInstanceEntity entity=new TaskInstanceEntity();

String id=task.getId();

entity.setCreateTime(task.getCreateTime());

entity.setTaskName(task.getName());

entity.setProcessInstanceId(task.getProcessInstanceId());

entity.setTaskId(id);

Map processVariables = taskService.getVariables(id);

entity.setRequestUser(processVariables.get("requestUser").toString());

entity.setResourceId(processVariables.get("resourceId").toString());

entities.add(entity);

});

}

return entities;

public void handleTask(ParamObj paramObj) {

Map taskVariables = new HashMap<>();

String approved=paramObj.isApproved()?"Y":"N";

taskVariables.put("approved", approved);

//审核结果和审核意见都封装为jsON然后放在评论里,后续需要进行逆操作。

ObjectMapper objectMapper = new ObjectMapper();

Map map= new HashMap<>();

map.put("approved", approved);

map.put("comment", paramObj.getComment());

try {

String json = objectMapper.writeValueAsString(map);

taskService.addComment(paramObj.getTaskId(), null, json);

taskService.complete(paramObj.getTaskId(), taskVariables);

} catch (Exception e) {

throw new RuntimeException(e);

public List queryProcessStatus(String processInstanceId) {

List result = new ArrayList<>();

List historicTaskInstances = historyService.createHistoricTaskInstanceQuery()

.processInstanceId(processInstanceId).list();

if(CollectionUtils.isEmpty(historicTaskInstances)) {

throw new RuntimeException("Process instance [" + processInstanceId + "] not exist");

for (HistoricTaskInstance hti : historicTaskInstances) {

String taskId = hti.getId();

String taskName = hti.getName();

String assignee = hti.getAssignee();

Date createTime = hti.getCreateTime();

String comment = null;

String approved=null;

List comments = taskService.getTaskComments(taskId);

if (!CollectionUtils.isEmpty(comments)) {

comment = comments.get(0).getFullMessage();

if(null!=comment) {

//这里进行评论的JSON数据的逆操作提取数据

ObjectMapper mapper = new ObjectMapper();

try {

Map data = mapper.readValue(comment, Map.class);

approved=data.get("approved").toString();

comment=data.get("comment").toString();

} catch (Exception e) {

System.out.println(e.toString());

}

}

}

ProcessStatusEntity pd=new ProcessStatusEntity();

pd.setTaskName(taskName);

pd.setAssignee(assignee);

pd.setCreateTime(createTime);

pd.setApproved(approved);

pd.setComment(comment);

pd.setTaskId(hti.getId());

pd.setProcessInstanceId(hti.getProcessInstanceId());

result.add(pd);

return result;

public Map queryProcessVariables(String processInstanceId) {

List historicVariableInstances =

historyService.createHistoricVariableInstanceQuery()

if (historicVariableInstances == null) {

Map ret= new HashMap<>();

for(HistoricVariableInstance var: historicVariableInstances) {

ret.put(var.getVariableName(), var.getValue());

return ret;

public List queryHistoryProcess(String assignee) {

List result=new ArrayList<>();

List activities = historyService.createHistoricActivityInstanceQuery()

.taskAssignee(assignee).finished().orderByHistoricActivityInstanceEndTime().desc().list();

for(HistoricActivityInstance h : activities) {

HistanceInstanceEntity d=new HistanceInstanceEntity();

d.setProcessInstanceId(h.getProcessInstanceId());

d.setTaskId(h.getTaskId());

d.setStartTime(h.getStartTime());

d.setEndTime(h.getEndTime());

result.add(d);

public void genProcessDiagram(HttpServletResponse httpServletResponse,

String processInstanceId) throws Exception{

ProcessInstance pi = runtimeService.createProcessInstanceQuery().

processInstanceId(processInstanceId).singleResult();

//流程走完的不显示图

if (pi == null) {

// System.out.println("不存在该流程或则流程已经走完");

throw new RuntimeException("不存在该流程或则流程已经走完");

// return;

Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();

//使用流程实例ID,查询正在执行的执行对象表,返回流程实例对象

String InstanceId = task.getProcessInstanceId();

List executions = runtimeService

.createExecutionQuery()

.processInstanceId(InstanceId)

.list();

//得到正在执行的Activity的Id

List activityIds = new ArrayList<>();

List flows = new ArrayList<>();

for (Execution exe : executions) {

List ids = runtimeService.getActiveActivityIds(exe.getId());

activityIds.addAll(ids);

//获取流程图

BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());

ProcessEngineConfiguration engineConf = processEngine.getProcessEngineConfiguration();

ProcessDiagramGenerator diagramGenerator = engineConf.getProcessDiagramGenerator();

InputStream in = diagramGenerator.generateDiagram(bpmnModel,

"png",

activityIds,

flows,

engineConf.getActivityFontName(),

engineConf.getLabelFontName(),

engineConf.getAnnotationFontName(),

engineConf.getClassLoader(),

1.0,true);

OutputStream out = null;

byte[] buf = new byte[1024];

int length = 0;

out = httpServletResponse.getOutputStream();

while ((length = in.read(buf)) != -1) {

out.write(buf, 0, length);

} finally {

if (in != null) {

in.close();

if (out != null) {

out.close();

public boolean isExistHistoricProcessInstance(String processInstanceId) {

HistoricProcessInstance historicProcessInstance =

historyService.createHistoricProcessInstanceQuery().

processInstanceId(processInstanceId).singleResult();

if (historicProcessInstance == null) {

return false;

return true;

public boolean isExistRunningProcessInstance(String processInstanceId) {

ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().

if (processInstance == null) {

public void suspendProcessInstance(String processInstanceId) {

runtimeService.suspendProcessInstanceById(processInstanceId);

public void terminateProcessInstance(ParamObj paramObj) {

runtimeService.deleteProcessInstance(paramObj.getProcessInstanceId(),paramObj.getDeleteReason());

public void activateProcessInstance(String processInstanceId) {

runtimeService.activateProcessInstanceById(processInstanceId);

public void deleteProcessInstance(ParamObj paramObj) {

//查询是否操作

long count = runtimeService.createExecutionQuery().processInstanceId(paramObj.getProcessInstanceId()).count();

if(count>0){

DeleteFlowableProcessInstanceCmd cmd=

new DeleteFlowableProcessInstanceCmd(paramObj.getProcessInstanceId(),

paramObj.getDeleteReason(),true);

managementService.executeCommand(cmd);

//runtimeService.deleteProcessInstance(processInstanceId,deleteReason);

}else{

//删除历史数据的流程实体

historyService.deleteHistoricProcessInstance(paramObj.getProcessInstanceId());

public void rollbackTask(String taskId, String targetTaskKey) {

Task currentTask = taskService.createTaskQuery().taskId(taskId).singleResult();

if (currentTask == null) {

return ;

List key = new ArrayList<>();

key.add(currentTask.getTaskDefinitionKey());

runtimeService.createChangeActivityStateBuilder()

.processInstanceId(currentTask.getProcessInstanceId())

.moveActivityIdsToSingleActivityId(key, targetTaskKey)

.changeState();

public boolean isProcessFinished(String processInstanceId) {

return historyService.createHistoricProcessInstanceQuery().finished()

.processInstanceId(processInstanceId).count()>0;

}

实现类中注入的变量都是flowable框架中的变量,实现类中的方法的作用在接口中都有向相关注释,其中deleteProcessInstance方法中会引用一个类来删除流程实例,DeleteFlowableProcessInstanceCmd类的定义如下:

@Data

public class DeleteProcessInstanceCmd implements Command, Serializable {

String processInstanceId;

String deleteReason;

//是否删除历史

boolean cascade=true;

public DeleteProcessInstanceCmd(){

}

public DeleteProcessInstanceCmd(String processInstanceId,String deleteReason){

this.deleteReason=deleteReason;

this.processInstanceId=processInstanceId;

}

public DeleteProcessInstanceCmd(String processInstanceId,

String deleteReason,

boolean cascade){

this.deleteReason=deleteReason;

this.processInstanceId=processInstanceId;

this.cascade=cascade;

}

@Override

public Void execute(CommandContext commandContext) {

ExecutionEntity entity= CommandContextUtil.getExecutionEntityManager(commandContext)

.findById(processInstanceId);

if(entity!=null){

if(entity.isDeleted()){

return null;

}

if(Flowable5Util.isFlowable5ProcessDefinitionId(commandContext,entity.getProcessDefinitionId())){

Flowable5CompatibilityHandler handler=Flowable5Util.getFlowable5CompatibilityHandler();

handler.deleteProcessInstance(processInstanceId,deleteReason);

}else{

CommandContextUtil.getExecutionEntityManager(commandContext).deleteProcessInstance(entity.getProcessInstanceId(),deleteReason,cascade);

}

}

return null;

}

}

上述功能了类定义完毕后,就可以创建我们的controller类了,我们的controller类的定义如下:

@RestController

@RequestMapping("/flowableTest")

public class FlowableController {

@Autowired

IProcess process;

@PostMapping("/startProcess")

public ProcessInstanceEntity startProcess(@RequestBody ParamObj paramObj){

return process.startProcess(paramObj);

}

@GetMapping("/getTaskInstance/{assignee}")

public List taskInstance(@PathVariable("assignee") String assignee){

return process.taskInstance(assignee);

}

@PutMapping("/handleTask")

public String handleTask(@RequestBody ParamObj paramObj){

process.handleTask(paramObj);

return "success";

}

@GetMapping("/queryProcessStatus")

public List queryProcessStatus(String processInstanceId){

return process.queryProcessStatus(processInstanceId);

}

@GetMapping("/queryProcessVariables")

public Map queryProcessVariables(String processInstanceId){

return process.queryProcessVariables(processInstanceId);

}

@GetMapping("/queryHistoryProcess")

public List queryHistoryProcess(String assignee){

return process.queryHistoryProcess(assignee);

}

@GetMapping("/genProcessDiagram")

public void genProcessDiagram(HttpServletResponse httpServletResponse,

String processInstanceId) throws Exception {

process.genProcessDiagram(httpServletResponse,processInstanceId);

}

@GetMapping("/isExistHistoricProcessInstance")

public boolean isExistHistoricProcessInstance(String processInstanceId){

return process.isExistHistoricProcessInstance(processInstanceId);

}

@GetMapping("/isProcessFinished")

public boolean isProcessFinished(String processInstanceId){

return process.isProcessFinished(processInstanceId);

}

@GetMapping("/isExistRunningProcessInstance")

public boolean isExistRunningProcessInstance(String processInstanceId){

return process.isExistRunningProcessInstance(processInstanceId);

}

@PutMapping("/suspendProcessInstance")

public String suspendProcessInstance(String processInstanceId){

process.suspendProcessInstance(processInstanceId);

return "流程 "+processInstanceId+" 已经挂起";

}

@PutMapping("/terminateProcessInstance")

public String terminateProcessInstance(ParamObj paramObj){

process.terminateProcessInstance(paramObj);

return "流程 "+paramObj.getProcessInstanceId()+" 已经终止";

}

@PutMapping("/activateProcessInstance")

public String activateProcessInstance(String processInstanceId) {

process.activateProcessInstance(processInstanceId);

return "流程 "+processInstanceId+" 已经激活";

}

@PutMapping("/deleteProcessInstance")

public String deleteProcessInstance(ParamObj paramObj){

process.deleteProcessInstance(paramObj);

return "流程 "+paramObj.getProcessInstanceId()+" 已经删除";

}

@PutMapping("/rollback")

public String rollbackTask(String taskId, String targetTaskKey){

process.rollbackTask(taskId,targetTaskKey);

return "流程回退成功";

}

}

试运行工程,运行工程后,系统会自动生成一些表单,是一些act_和flw_开头的表单,如下,利用postman创建一个流程实例:

查看流程示例图:

调用查看任务接口,可以查看某个人有哪些任务需要处理:

调用任务处理接口:

查看处理后的结果:

以上是flowable流程框架的简单应用,更为详细的使用等待后续的挖掘......


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:springBoot配置国产达梦数据库的示例详解
下一篇:利用Java代码实现区块链技术
相关文章

 发表评论

暂时没有评论,来抢沙发吧~