微前端架构如何改变企业的开发模式与效率提升
1152
2022-10-12
springboot整合flowable框架入门步骤
最近工作中有用到工作流的开发,引入了flowable工作流框架,在此记录一下springboot整合flowable工作流框架的过程,以便后续再次使用到时可以做一些参考使用,如果项目中有涉及到流程审批的话,可以使用该框架帮我们实现流程图示化展示的功能,为了快速了解flowable工作流框架的一个使用过程,我们直接步入主题,springboot整合flowable工作流框架的步骤如下:
1、首先创建一个springboot工程,然后引入flowable pom依赖,代码如下:
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
/**
* 处理工作
* @param paramObj
*/
void handleTask(ParamObj paramObj);
/**
* 获取某个流程实体的状态,各个审批环节所处的状态信息
* @param processInstanceId
* @return
*/
List
/**
* 查看创建流程实例时登记的变量信息
* @param processInstanceId
* @return
*/
Map
/**
* 获取某人的历史审批数据
* @param assignee
* @return
*/
List
/**
* 生成流程的图谱
* @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
// 请求的资源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
List
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
entity.setRequestUser(processVariables.get("requestUser").toString());
entity.setResourceId(processVariables.get("resourceId").toString());
entities.add(entity);
});
}
return entities;
public void handleTask(ParamObj paramObj) {
Map
String approved=paramObj.isApproved()?"Y":"N";
taskVariables.put("approved", approved);
//审核结果和审核意见都封装为jsON然后放在评论里,后续需要进行逆操作。
ObjectMapper objectMapper = new ObjectMapper();
Map
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
List
List
.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
if (!CollectionUtils.isEmpty(comments)) {
comment = comments.get(0).getFullMessage();
if(null!=comment) {
//这里进行评论的JSON数据的逆操作提取数据
ObjectMapper mapper = new ObjectMapper();
try {
Map
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
List
historyService.createHistoricVariableInstanceQuery()
if (historicVariableInstances == null) {
Map
for(HistoricVariableInstance var: historicVariableInstances) {
ret.put(var.getVariableName(), var.getValue());
return ret;
public List
List
List
.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
.createExecutionQuery()
.processInstanceId(InstanceId)
.list();
//得到正在执行的Activity的Id
List
List
for (Execution exe : executions) {
List
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.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
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
return process.taskInstance(assignee);
}
@PutMapping("/handleTask")
public String handleTask(@RequestBody ParamObj paramObj){
process.handleTask(paramObj);
return "success";
}
@GetMapping("/queryProcessStatus")
public List
return process.queryProcessStatus(processInstanceId);
}
@GetMapping("/queryProcessVariables")
public Map
return process.queryProcessVariables(processInstanceId);
}
@GetMapping("/queryHistoryProcess")
public List
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小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~