SpringBoot+Flowable快速实现工流_动态选择审批人员
前言
OA系统中的工作流不仅是企业日常运营的重要组成部分,也是实现企业数字化转型、提高工作效率和执行力的重要工具。 在国内大部分的工作流系统使用Activiti框架实现。 其实flowable也可以轻松实现工作流业务。在线体验JeecgFlow
flowable简介
Flowable是一个使用Java编写的轻量级业务流程引擎。它主要用于部署BPMN 2.0流程定义(一种用于定义流程的行业XML标准),创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程实例与相关数据等。Flowable流程引擎的特点包括灵活性和可扩展性,提供了图形化的流程设计器,可以与规则引擎集成,支持多种执行环境,并且可以轻易地加入任何Java环境。
版本信息
Flowable 6.7.2
SpringBoot 2.7.12
SpringBoot整合flowable
maven依赖
<flowable.spring-boot.version>6.7.2</flowable.spring-boot.version<dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>${flowable.spring-boot.version}</version><exclusions><exclusion><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></exclusion></exclusions>
</dependency>
配置
flowable:#关闭定时任务JOBasync-executor-activate: false#将databaseSchemaUpdate设置为true。当flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。database-schema-update: true# 自动部署验证设置:true-开启(默认)、false-关闭check-process-definitions: false#保存历史数据级别设置为full最高级别,便于历史数据的追溯history-level: full
简单两步,就可以启动boot应用。初次运行时flowable会将自动执行flowable中的初始化脚本完成工作流所需要的数据表的建立,如果指定的数据库中还未创建过flowable的相关数据表的话。
流程定义
假设现在有一个请假需求,用户提交申请表单后, 直属领导进行审批操作。 可以是通过或拒绝。并且要求不同部门的人员绑定所属的领导。 Bpmn在线建模
申请节点,定义用户提交数据的字段
申请节点, 设置了任务完成后的监听器。用于动态设置审批领导的名称。
直属领导申请的节点属性设置。
xml内容
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn"><bpmn:process id="Process_choose_leader" name="动态审批" isExecutable="true"><bpmn:startEvent id="StartEvent_1"><bpmn:outgoing>Flow_09w75kg</bpmn:outgoing></bpmn:startEvent><bpmn:sequenceFlow id="Flow_09w75kg" sourceRef="StartEvent_1" targetRef="Activity_1xn21s1" /><bpmn:userTask id="Activity_1xn21s1" name="申请" camunda:assignee="${general}"><bpmn:extensionElements><camunda:formData><camunda:formField id="days" label="请假天数" type="long" defaultValue="1" /><camunda:formField id="reason" label="请假理由" type="string" /><camunda:formField id="type" label="请假类型" type="string" /></camunda:formData><camunda:taskListener delegateExpression="${chooseLeaderListener}" event="complete" /></bpmn:extensionElements><bpmn:incoming>Flow_09w75kg</bpmn:incoming><bpmn:outgoing>Flow_1n7z9g2</bpmn:outgoing></bpmn:userTask><bpmn:sequenceFlow id="Flow_1n7z9g2" sourceRef="Activity_1xn21s1" targetRef="Activity_0474tsq" /><bpmn:userTask id="Activity_0474tsq" name="直属领导" camunda:assignee="${leader}"><bpmn:extensionElements><camunda:formData><camunda:formField id="comment" label="评论" type="string" /><camunda:formField id="imageUrl" label="图片" type="string" /></camunda:formData></bpmn:extensionElements><bpmn:incoming>Flow_1n7z9g2</bpmn:incoming><bpmn:outgoing>Flow_1lyuw6k</bpmn:outgoing></bpmn:userTask><bpmn:endEvent id="Event_10twye6"><bpmn:incoming>Flow_1lyuw6k</bpmn:incoming></bpmn:endEvent><bpmn:sequenceFlow id="Flow_1lyuw6k" sourceRef="Activity_0474tsq" targetRef="Event_10twye6" /></bpmn:process></bpmn:definitions>
代码编写
开始流程
@ApiOperation(value = "发起请假", notes = "提交请假的数据")
@PostMapping("start")
public Result<?> start(@RequestBody LeaveStartReq leaveStartReq) {log.info("start.leaveStartReq:{}", leaveStartReq);ValidatorUtils.validateEntity(leaveStartReq);//查询登陆用户String id = SecurityContextHolder.getContext().getAuthentication().getName();User loginUser = userService.getById(id);//发起流程并初始化各个用户任务节点的指定人Authentication.setAuthenticatedUserId(Optional.ofNullable(loginUser).map(m -> m.getUsername()).orElse("xxx"));Map<String, Object> variables = new HashMap<>(4);variables.put("general", Optional.ofNullable(loginUser).map(m -> m.getUsername()).orElse("mark"));ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(FlowConstant.MODEL_KEY_LEAVE, variables);//执行一个申请节点的动作userTaskService.completeApplyUserTask(processInstance.getId(), loginUser, leaveStartReq);return Results.newSuccessResult(processInstance.getId());
}
以上逻辑就是发起流程, 核心步骤就是获取登陆用户信息,并且设置流程启动参数。 在流程启动后完成第一个用户任务节点。此时流程便可以往下面流转。
完成申请任务的监听事件
@Component("chooseLeaderListener")
@Slf4j
public class ChooseLeaderListener implements TaskListener {@Autowiredprivate ISysBaseAPI sysBaseAPI;@Overridepublic void notify(DelegateTask delegateTask) {log.info("动态选择下一个用户任务节点审批人员监听器");//查询发起用户所属的部门Id集合String startUser = String.valueOf(delegateTask.getVariable("general"));List<String> myDeptIds = sysBaseAPI.getDepartIdsByUsername(startUser);//根据部门id查询负责人List<String> leaderList = new ArrayList<>();for (String myDeptId : myDeptIds) {leaderList.addAll(sysBaseAPI.getDeptHeadByDepId(myDeptId));}log.info("直属部门领导人员:{}", leaderList);//设置下一个审批节点的用户名称,注意如何是有多个领导需要同时审批,要把审批节点设置为多实例。if(CollectionUtil.isNotEmpty(leaderList)){delegateTask.setVariable("leader", leaderList.get(0));}}
}
在上一步申请节点完成后,将执行任务监听起逻辑,查询到下一个节点的审批用户名称。并且绑定到leader流程变量。此时便可以实现不同部门有不同领导。
审批通过
public void pass(PassReq passReq, User loginUser) {Task task = taskService.createTaskQuery().processInstanceId(passReq.getProcessInstanceId()).taskAssignee(loginUser.getUsername()).singleResult();//完成用户任务Map<String, Object> map = new HashMap<>(12);map.put("comment", passReq.getContent());map.put("imageUrl", imageUrl);taskService.complete(task.getId(), map);
}
审批通过操作的核心逻辑。 驳回就留给大家自己研究了。
运行效果的图
通过Springboot+flowable就是这么简单, 在线体验JeecgFlow