springboot2整合flowable工作流,实现请假流程审批

发布时间:2019-10-24
技术:springboot2.1.1+flowable6.4.2+mysql

概述

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没有。

1571888148388086841.png

ProcessEngine

最核心的类,其他的类都是由他而来,由工作流引擎可以创建各个Service,这些Service是调用工作流23张表的服务


RepositoryService

仓库服务类。所谓的仓库指流程定义文档的两个文件:bpmn文件和流程图片。


RuntimeService

流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。


TaskService

任务服务类。可以从这个类中获取任务的信息。


HistoryService

查询历史信息的类。在一个流程执行完成后,这个对象为我们提供查询历史信息。


ProcessDefinition

流程定义类。可以从这里获得资源文件等。


ProcessInstance

代表流程定义的执行实例。如小明请了一天的假,就必须发出一个流程实例的申请。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个。


Execution

用这个对象去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。

三、代码分析

1571888641281000737.png

如图: 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();
            }
        }
	}

四、项目文件结构

image.png

五、启动部署流程

首先 在mysql创建数据库flowable,  在数据库执行sqlj脚本: flowable.mysql.all.create.sql. 

然后,eclipse导入maven项目, 配置mysql数据源

image.png


最后,待maven依赖jar包加载完成后, 右击FlowableApplication直接运行就可以了.

image.png

六、演示效果

1. 登陆

系统安排了三个用户,  el (员工),  tl1(主管1), tl2 (主管2)


2.el登陆,点击 请假候选人审批, 填写请假信息.

image.png

image.png

3. 登陆tl1或者tl2 , 点击申请新任务

image.png

image.png4. 查看流程图

image.png

本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
手机上随时阅读、收藏该文章 ?请扫下方二维码