Flowable工作流引擎的使用3(task审批节点的接受与使用)

BPMN task节点

节点介绍

image-20211014133529840

task节点是和业务最贴切的节点,表示一次审批

除了id,name,inComingFlows,outGoingFlows这些属性以外,还有一些权限信息.用于区分一个任务哪些人可以审核的

flowable自带一个ui配置界面,很多的数据库表设计都是和ui界面挂钩的,所以数据库会有很多我们不是很理解的字段,官方文档说明

public class UserTask extends Task {
    protected String assignee;
    protected String owner;
    protected String priority;
    protected String formKey;
    protected String dueDate;
    protected String businessCalendarName;
    protected String category;
    protected String extensionId;
    protected List<String> candidateUsers = new ArrayList<>();
    protected List<String> candidateGroups = new ArrayList<>();
    protected List<FormProperty> formProperties = new ArrayList<>();
    protected List<FlowableListener> taskListeners = new ArrayList<>();
    protected String skipExpression;
}

其中有很多属性,form表单,候选组候选人,待办人等等,非常多的概念

image-20211014134002205

实际项目中,我们肯定是走自己的权限系统,不会走flowable里的权限系统,所以,我们在配置BPMN的时候,可以使用一些取巧的方式.

flowable的这么多属性最终会保存到数据库中的,我们只需要将我们的业务id存储进来,然后不同的业务员通过自己的员工id,能够查询到待审批的流程即可.可以不用关心这些属性值在flowable究竟是什么意义,对我们而言就是一个塞业务id的一个列而已.

  • owner 表示流程的拥有者

  • candidateGroups 候选组, 当一个userTask节点同时存在owner和candidateGroups的时候,owner会变为空

  • assignee 表示任务受让人,当我们不指定的时候为空

  • skipExpression 表示跳过表达式,如果多级审批人都是同一个人,可以考虑跳过同一个人的下面几个审批,解决烦人的多次审核问题

借助owner和candidateGroups这两点,我们基本上可以完成我们审批人权限数据的填入了.

example

前端先获取机构人员id的下拉框,然后塞进流程引擎的candidateGroups里面,传给后端

image-20211014134320800

查询待办的时候,通过当前系统登录人员工id来查询即可

image-20211014134757616

  • 如果业务中,我们的一个节点只能是一个人审核,那么我们直接给owner赋值一个业务id即可

  • 如果可以是多个人进行审核,那么我们就把多个id权限字段存储到一个List’<‘String’>'里,然后传入candidateGroups里

  • 如果一个字段不够用,可以用 : 进行字符串拼接 , 比如 {公司id}:{部门id}:{员工id}

  • 如果我们的流程需要让另一个小哥进行审核,比如原员工跑路了,那么我们可以把这个受让人属性设置为新的审批人权限id

伪代码如下

List<String> auditors = new ArrayList<>();
//有代理人,代理人就是审批人
if(userTask.getAssignee() != null){
   auditors.add(userTask.getAssignee());
}
//没有代理人,但是候选组不为空,所有候选组的人都是待审核的人
if(CollectionUtils.isNotEmpty(userTask.getCandidateGroups()){
  auditors.addAll(userTask.getCandidateGroups());
}
else{
  //审批人只有一个人
  auditors.add(userTask.getOwner());
}

还有一种方式

image-20211014135158101

  • 如果觉得这样改flowable数据库表的用法不太好,我们可以跳出flowable,自己先创建一个权限关系表,绑定好flowable的流程,先通过权限关系表拿到这个人可以审核的流程的一些信息,再结合这些进行去查询流程,查询到的待审批的任务就是我们的当前登录人可以审批的任务节点了

  • 流程引擎的这些权限主要还是针对于查询,实际上我们调用推动流程的方法时,流程引擎并不会去校验权限,只要有taskId,processsId调用推动流程API即可,所以对于非Sass系统,非权限系统,仅限于一个简单的流程配置给一个系统使用,userTask的这些owner,assignee,candidateGroups这些属性都可以为空.那么我们查询流程都通过流程id来查询即可

介绍完userTask的一些属性,我们结合例子来说明一下,如何在实际项目开发中使用到这些属性

BPMN配置userTask节点

这里用官方的绘图工具,下载以及启动可以参考这一篇博客链接

先绘制一个最简单的流程

image-20211014104446442

给流程设置审批组

image-20211014110328192

身份存储需要先从flowable的权限系统注册一个审批人信息,太重了.

我们这边直接使用固定值的形式,添加两个候选人名字的字符串

image-20211014110047034

添加好了保存,然后导出bpmn20.xml文件,该编辑器详细界面参考这篇博文链接

image-20211014111120111

得到bpmn图,这里id和name属性都会自动生成

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
  <process id="key" name="demo" isExecutable="true">
    <documentation>demo</documentation>
    <!-- 开始节点	-->
    <startEvent id="startEvent1" flowable:initiator="sponsor" flowable:formFieldValidation="true"></startEvent>
    <!-- 第一个审核节点 有jakt和jack两个候选人	-->
    <userTask id="sid-AD4D3CCF-4705-4F03-A381-269C354AB992" flowable:candidateGroups="jakt,jack" flowable:formFieldValidation="true"></userTask>
    <userTask id="sid-3FBBAF8C-F882-49B8-9723-3A3D163B6E8B" flowable:formFieldValidation="true"></userTask>
    <endEvent id="sid-F95597D2-838C-46BD-95D2-4CD0C7B41A17"></endEvent>
    <sequenceFlow id="sid-1D4DE32E-2FE6-4E4B-A95F-82265E6893B1" sourceRef="startEvent1" targetRef="sid-AD4D3CCF-4705-4F03-A381-269C354AB992"></sequenceFlow>
    <sequenceFlow id="sid-5FF980E1-87E8-4F72-A5B6-6D549367C797" sourceRef="sid-3FBBAF8C-F882-49B8-9723-3A3D163B6E8B" targetRef="sid-F95597D2-838C-46BD-95D2-4CD0C7B41A17" skipExpression="{outcome}=='通过'"></sequenceFlow>
    <sequenceFlow id="sid-295254FA-B051-423E-B3EE-091421844E7B" sourceRef="sid-AD4D3CCF-4705-4F03-A381-269C354AB992" targetRef="sid-3FBBAF8C-F882-49B8-9723-3A3D163B6E8B" skipExpression="{outcome}=='通过'"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_key">
    <bpmndi:BPMNPlane bpmnElement="key" id="BPMNPlane_key">
      <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
        <omgdc:Bounds height="30.0" width="30.0" x="90.0" y="175.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-AD4D3CCF-4705-4F03-A381-269C354AB992" id="BPMNShape_sid-AD4D3CCF-4705-4F03-A381-269C354AB992">
        <omgdc:Bounds height="80.0" width="100.0" x="300.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-3FBBAF8C-F882-49B8-9723-3A3D163B6E8B" id="BPMNShape_sid-3FBBAF8C-F882-49B8-9723-3A3D163B6E8B">
        <omgdc:Bounds height="80.0" width="100.0" x="603.5" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-F95597D2-838C-46BD-95D2-4CD0C7B41A17" id="BPMNShape_sid-F95597D2-838C-46BD-95D2-4CD0C7B41A17">
        <omgdc:Bounds height="28.0" width="28.0" x="915.0" y="176.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-295254FA-B051-423E-B3EE-091421844E7B" id="BPMNEdge_sid-295254FA-B051-423E-B3EE-091421844E7B">
        <omgdi:waypoint x="399.95000000000005" y="190.0"></omgdi:waypoint>
        <omgdi:waypoint x="603.4999999998836" y="190.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-1D4DE32E-2FE6-4E4B-A95F-82265E6893B1" id="BPMNEdge_sid-1D4DE32E-2FE6-4E4B-A95F-82265E6893B1">
        <omgdi:waypoint x="119.94999969544602" y="190.0"></omgdi:waypoint>
        <omgdi:waypoint x="300.0" y="190.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-5FF980E1-87E8-4F72-A5B6-6D549367C797" id="BPMNEdge_sid-5FF980E1-87E8-4F72-A5B6-6D549367C797">
        <omgdi:waypoint x="703.4499999999911" y="190.0"></omgdi:waypoint>
        <omgdi:waypoint x="915.0" y="190.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

我们将BPMN文件导入项目,然后再导出看看

@CrossOrigin(origins = "*", maxAge = 3600)
@GetMapping("/loading")
public ResultData<String> loading() throws FileNotFoundException {
  //先部署流程模板
  Deployment deployment = repositoryService
    .createDeployment()
    .tenantId(companyName)
    .addInputStream("demo.bpmn20.xml", new FileInputStream(ResourceUtils.getFile("classpath:demo.bpmn20.xml")))
    .deploy();
//再查看流程对象
  ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
    .processDefinitionKey("key")
    .processDefinitionTenantId(companyName)
    .singleResult();
  BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
  System.out.println(bpmnModel);
  return ResultData.ofSuccess();
}

这里我偷懒了,直接打断点了,可以看到我们配置的信息都生效了

bpmnModel ==> processes ==> flowElementList ==> userTask ==> candidateGroups=> {‘jack’,‘jakt’}

image-20211014113401277

我们现在开启这个流程,然后再查询流程进度

@CrossOrigin(origins = "*", maxAge = 3600)
@GetMapping("/createTaskByKey")
public ResultData<String> createTaskByKey(@RequestParam String id) {
  //设置发起人
  Authentication.setAuthenticatedUserId("jakt");
  ProcessInstance processInstance = runtimeService.startProcessInstanceByKeyAndTenantId(key, companyName);
  ResultData<String> stringResultData = ResultData.ofSuccess(processInstance.getId());
  Authentication.setAuthenticatedUserId(null);
  return stringResultData;
}

先不设置查询条件,直接全表查询

@CrossOrigin(origins = "*", maxAge = 3600)
@GetMapping("/queryAllTask")
public ResultData<String> queryAllTask(String id) {
  //全查再说
  System.out.println(taskService.createTaskQuery().list());
  return ResultData.ofSuccess();
}

我们目前有一个任务task,然后owner是空的,因为我们确实没设置

image-20211014114046162

接下里我们加个查询条件

jakt是属于候选人(jakt,jack)中的,我们加一个条件试试,确实拿到了

image-20211014114145055

我换一个查询条件,嗯没有数据了.

通过这candidateGroups字段,我们就可以实现最简单的数据权限了

image-20211014114156550

总结

  • 设置一个task节点的数据权限,然后我们结合我们业务系统的权限id来查询流程就可以实现审批人权限控制了
  • flowable的userTask对象的很多属性都是适配于其自带的模型的一些功能而定制的如果我们只是用flowable的后台API接口的话,可以稍加修改就可以适配我们现有的代码
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
flowable工作流可以应用于各种场景,包括但不限于以下几个方面: 1. 自动化流程flowable工作流可以帮助实现各种自动化流程,例如审批流程、订单流程、报销流程等。通过定义流程模型、任务节点和流转规则,可以使得流程的执行自动化、标准化,并且可以方便地进行监控和管理。 2. 业务流程优化:对于复杂的业务流程,可以使用flowable工作流来进行流程的优化和重构。通过将业务逻辑与流程逻辑分离,可以更好地管理和维护业务流程,并且可以灵活地进行流程的调整和修改。 3. 异步任务处理:flowable工作流支持异步任务处理,可以将一些需要耗时的操作放在异步任务中进行处理,提高系统的性能和响应速度。 4. 并发控制:flowable工作流可以帮助实现并发控制,例如资源的争抢、并发访问控制等。通过使用流程实例、任务和锁机制,可以有效地控制并发操作的顺序和执行结果。 5. 监控和统计:flowable工作流可以提供流程的监控和统计功能,包括流程的执行情况、执行时间、耗时统计等。通过这些统计数据,可以对流程进行性能分析和优化,提高系统的效率和可靠性。 总结来说,flowable工作流可以在各种场景下使用,帮助实现流程的自动化、优化和管理,并且可以提供监控和统计功能。它可以帮助简化业务逻辑,提高系统的性能和可维护性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [工作流入门教程(flowable框架)](https://blog.csdn.net/qq_25542879/article/details/107048660)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [flowable工作流.zip](https://download.csdn.net/download/weixin_43726137/73501882)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值