springboot2整合flowable工作流,实现请假流程审批
概述
详细
一、需求
基于springboot2整合flowable实现: 1. 请假流程审批. 员工请假-->主管审批-->hr审批. 2. 请假候选人审批, 员工请假-->主管1审批/主管2审批
二、理论概述
三大主流工作流引擎:Shark,osworkflow,jbpm!
shark:系统和功能都比较复杂
Osworkflow:比较灵活的轻量级的框架,但是在流程建模方面不太友好,需要手动编写xml文件去定义流程文件。
Activiti 基于jbmp4开源代码而来。传言是要替换掉jbmp。
Flowable已经修复了activiti6很多的bug,可以实现零成本从activiti迁移到flowable。
flowable目前已经支持加签、动态增加实例中的节点、支持cmmn、dmn规范。这些都是activiti6目前版本没有的。
1、flowable已经支持所有的历史数据使用mongdb存储,activiti没有。
2、flowable支持事务子流程,activiti没有。
3、flowable支持多实例加签、减签,activiti没有。
4、flowable支持httpTask等新的类型节点,activiti没有。
5、flowable支持在流程中动态添加任务节点,activiti没有。
6、flowable支持历史任务数据通过消息中间件发送,activiti没有。
7、flowable支持java11,activiti没有。
8、flowable支持动态脚本,,activiti没有。
9、flowable支持条件表达式中自定义juel函数,activiti没有。
10、flowable支持cmmn规范,activiti没有。
11、flowable修复了dmn规范设计器,activit用的dmn设计器还是旧的框架,bug太多。
12、flowable屏蔽了pvm,activiti6也屏蔽了pvm(因为6版本官方提供了加签功能,发现pvm设计的过于臃肿,索性直接移除,这样加签实现起来更简洁、事实确实如此,如果需要获取节点、连线等信息可以使用bpmnmodel替代)。
13、flowable与activiti提供了新的事务监听器。activiti5版本只有事件监听器、任务监听器、执行监听器。
14、flowable对activiti的代码大量的进行了重构。
15、activiti以及flowable支持的数据库有h2、hsql、mysql、oracle、postgres、mssql、db2。其他数据库不支持的。使用国产数据库的可能有点失望了,需要修改源码了。
16、flowable支持jms、rabbitmq、mongodb方式处理历史数据,activiti没有。
ProcessEngine
最核心的类,其他的类都是由他而来,由工作流引擎可以创建各个Service,这些Service是调用工作流23张表的服务
RepositoryService
仓库服务类。所谓的仓库指流程定义文档的两个文件:bpmn文件和流程图片。
RuntimeService
流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。
TaskService
任务服务类。可以从这个类中获取任务的信息。
HistoryService
查询历史信息的类。在一个流程执行完成后,这个对象为我们提供查询历史信息。
ProcessDefinition
流程定义类。可以从这里获得资源文件等。
ProcessInstance
代表流程定义的执行实例。如小明请了一天的假,就必须发出一个流程实例的申请。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个。
Execution
用这个对象去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。
三、代码分析
如图: el提交申请, 由两个候选主管审批, tl1,tl2.
el提交请假申请
public Map<String, Object> createLeave() { // 流程启动 String id = "leaveProcess"; Map<String, Object> map = new HashMap<String, Object>(); runtimeService.addEventListener(new CustormEventListener()); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(id, map); log.info("----------创建流程ID------: {} " , processInstance.getId()); String assignee = "el";// 当前任务办理人 List<Task> tasks = taskService// 与任务相关的Service .createTaskQuery()// 创建一个任务查询对象 .taskAssignee(assignee) .processInstanceId(processInstance.getId()) .list(); log.info("el的任务数量: {} " , tasks.size()); Task task = tasks.get(0); return this.getTaskFormPropertyList(task.getId()); }
当el提交申请之后, tl1/tl2 可以根据意愿, 申请新的审批任务 .
@RequestMapping(value="/apply/task.json") @ResponseBody public Result<String> applyTask(ModelMap modelMap, HttpServletRequest request, HttpServletResponse response,HttpSession session) { String username =(String) session.getAttribute(SessionConst.SESSION_USERNAME_KEY); List<Task> list = taskService.createTaskQuery().taskCandidateUser(username).listPage(0, 1); if(null!=list && !list.isEmpty()) { Task task = list.get(0); taskService.claim(task.getId(), username); } return Result.success("1"); }
如果tl1/tl2申请到审批任务之后, 可以在自己的代办任务列表里看到此任务, 走正常审批流程.
我们可随时通过流程图接口,看到本次流程到哪一步了
@Override public void genProcessDiagram(HttpServletResponse httpServletResponse, String taskId) throws Exception { Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); String processId =task.getProcessInstanceId(); ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).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(); } } }
四、项目文件结构
五、启动部署流程
首先 在mysql创建数据库flowable, 在数据库执行sqlj脚本: flowable.mysql.all.create.sql.
然后,eclipse导入maven项目, 配置mysql数据源
最后,待maven依赖jar包加载完成后, 右击FlowableApplication直接运行就可以了.
六、演示效果
1. 登陆
系统安排了三个用户, el (员工), tl1(主管1), tl2 (主管2)
2.el登陆,点击 请假候选人审批, 填写请假信息.
3. 登陆tl1或者tl2 , 点击申请新任务
4. 查看流程图