springboot如何集成flowable,如何部署flowable在线编辑器画bpm图以及bpm图的画法,我在上一篇博客中写了,这里直接上代码。
这是我画的请假流程bpm图。
然会到代码部分。
首先,先写一个config类,避免生成的bpm图中文乱码。
package com.example.config; import org.flowable.spring.SpringProcessEngineConfiguration; import org.flowable.spring.boot.EngineConfigurationConfigurer; import org.springframework.context.annotation.Configuration; @Configuration public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> { @Override public void configure(SpringProcessEngineConfiguration springProcessEngineConfiguration) { springProcessEngineConfiguration.setActivityFontName("宋体"); springProcessEngineConfiguration.setLabelFontName("宋体"); springProcessEngineConfiguration.setAnnotationFontName("宋体"); } }
由于我在画bpm图的时候,给“经理审批”节点和“老板审批”节点设置了监听器。所以接下来写监听器类
- 经理审批节点监听器。指定任务受理人为“领导”。
package com.example.listen; import org.flowable.engine.delegate.TaskListener; import org.flowable.task.service.delegate.DelegateTask; public class ManagerTaskHandler implements TaskListener { @Override public void notify(DelegateTask delegateTask) { delegateTask.setAssignee("领导"); System.out.println("执行监听器————————————————————————————————————"); } }
- 老板审批节点监听器。指定任务受理人为“老板”。
package com.example.listen; import org.flowable.engine.delegate.TaskListener; import org.flowable.task.service.delegate.DelegateTask; public class BossTaskHandler implements TaskListener { @Override public void notify(DelegateTask delegateTask) { delegateTask.setAssignee("老板"); } }
接下来到controller。
- 发起请假流程。这里要说明一下,只有在上一个节点完成任务后,流程才会执行到下一个节点。所以这里在发起流程后,就手动完成了任务,让流程进行到下一个节点。
/** * 发起请假 * * @param userId 用户Id * @param days 请假天数 * @param descption 描述 */ @RequestMapping(value = "/add") @ResponseBody public String addExpense(String userId, Integer money, String descption) { //启动流程 HashMap<String, Object> map = new HashMap<>(); map.put("taskUser", userId); map.put("days", days); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leave-flow", map); Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult(); taskService.complete(task.getId()); return "提交成功.流程Id为:" + processInstance.getId() + "任务id: " + task.getId() ; }
- 其他操作。
/** * 获取审批管理列表 */ @RequestMapping(value = "/list") @ResponseBody public Object list(String userId) { List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list(); for (Task task : tasks) { } System.out.println(tasks.toString()); return tasks.toString(); } /** * 批准 * * @param taskId 任务ID */ @RequestMapping(value = "apply") @ResponseBody public String apply(String taskId) { List<Task> t = taskService.createTaskQuery().list(); Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); //Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); if (task == null) { throw new RuntimeException("流程不存在"); } //通过审核 HashMap<String, Object> map = new HashMap<>(); map.put("result", "同意"); taskService.complete(taskId, map); return "processed ok!"; } /** * 拒绝 */ @ResponseBody @RequestMapping(value = "reject") public String reject(String taskId) { HashMap<String, Object> map = new HashMap<>(); map.put("result", "驳回"); taskService.complete(taskId, map); return "reject"; } /** * 生成流程图 * * @param processId 任务ID */ @RequestMapping(value = "processDiagram") public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception { List<ProcessInstance> t = runtimeService.createProcessInstanceQuery().list(); 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); InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, Collections.emptyList(), engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), null, 1.0, false); 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(); } } }
测试。
- 发起流程。可以看到后台打印了监听器中的内容,说明执行了监听器。
- 获取审批列表。
- 通过经理审批。taskId可以从act_ru_task表中查看。
- 查看流程图。
- 老板驳回请求。
-
再次查看流程图。可以看到驳回请求后,又回到申请人节点。
- 如果老板也通过的话,整个流程就结束了。
整个流程到这里就演示完了。当时在学的时候,流程卡在第一个节点不往下执行,最后发现只有上一个节点任务完成,才会到下一个节点,发起人节点要手动完成任务。其实在实际开发中,当发起人提交表单时,任务也就完成了,流程会接着往下执行。
最后补充一下个人认为比较重要的几个表:
act_ru_execution:运行流程实例表。发起的运行中流程可以在此表中看到。
act_ru_task:运行时任务表。可以查看运行的任务id和任务执行到哪个节点。
act_re_procdef:已经发布定义的流程可以在此表中看到。
act_id_user:用户信息表。