以为用不到Activiti,没想到实习第一天被打脸

1,531 阅读9分钟

以前在图书馆看到过很多关于Activiti的书籍,但是不知道他是干什么的,只知道这玩意和Android中的Activity就差一个单词,天真的以为以后也用不上,殊不知,在实习第一天就被让学习Activiti,经过两天的研究,终于有了些眉目,所以在此记录下来,下面将会展示两个小案例,以此来入个门。

Activiti简介

Activiti是一个轻量级以Java为中心的开源BPMN引擎,可以发布设计好的流程定义,并通过api进行流程调度,满足现实世界中的流程自动化需求。

而BPMN是一种流程建模的通用和标准语言,用来绘制业务流程图,以便更好地让各部门之间理解业务流程和相互关系,旨在促进业务流程的沟通和理解。

对于Java开发者来说,Activiti的首席架构师Tom Baeyens曾提到,Activiti的首个目标就是要获得开发者的青睐。首先它在使用时极为方便,只是个jar文件,使用时仅需要将其放在类路径中,当然,Activiti也可以作为独立服务器的方式使用,同时Activiti提供了很多 BPM高级工具,其中还包括开发了协作工具,使得开发人员、业务人员和运维人员能够更好的协同工作。

以下是Activiti各个服务的功能简介:

  • RepositoryService: Activiti 中每一个不同版本的业务流程的定义都需要使用一些定义文件,部署文件和支持数据 ( 例如 BPMN2.0 XML 文件,表单定义文件,流程定义图像文件等 ),这些文件都存储在 Activiti 内建的 Repository 中。Repository Service 提供了对 repository 的存取服务。
  • RuntimeService:在 Activiti 中,每当一个流程定义被启动一次之后,都会生成一个相应的流程对象实例。Runtime Service 提供了启动流程、查询流程实例、设置获取流程实例变量等功能。此外它还提供了对流程部署,流程定义和流程实例的存取服务。
  • TaskService:在 Activiti 中业务流程定义中的每一个执行节点被称为一个 Task,对流程中的数据存取,状态变更等操作均需要在 Task 中完成。Task Service 提供了对用户 Task 和 Form 相关的操作。它提供了运行时任务查询、领取、完成、删除以及变量设置等功能。
  • IdentityService:Activiti 中内置了用户以及组管理的功能,必须使用这些用户和组的信息才能获取到相应的 Task。Identity Service 提供了对 Activiti 系统中的用户和组的管理功能。
  • ManagementService:Management Service 提供了对 Activiti 流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于 Activiti 系统的日常维护。
  • HistoryService: History Service 用于获取正在运行或已经完成的流程实例的信息,与 Runtime Service 中获取的流程信息不同,历史信息包含已经持久化存储的永久信息,并已经被针对查询优化。
  • FormService: Activiti 中的流程和状态 Task 均可以关联业务相关的数据。通过使用 Form Service 可以存取启动和完成任务所需的表单数据并且根据需要来渲染表单。

(工作流总是以任务(Task)的形式驱动人处理业务或者驱动业务系统自动完成作业。)

BPMN流程定义

设计BMPN工作流程图可以使用官方提供的一个工具,下载后将他放在tomcat的webapps下,然后启动tomcat,下面是登录界面,用户名和密码分别是admin、test。

进入之后选第一个,然后Create Process。

接下来我们做一个简单的流程,现在假设小明晚上回家后先做作业,然后打游戏,按照这个流程我们来写一个程序。

绘制好之后我们将他下载下来,是一个xml格式的,具体如何下载,这里就不说了,然后将他放在resources/processes路径下,activiti-app这个工具其实就是用来生成下面这些数据的。

activiti-test.bpmn20.xml内容如下:

<?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:activiti="http://activiti.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.activiti.org/processdef">
  <process id="activiti-test" name="activiti-test" isExecutable="true">
    <documentation>activiti-test</documentation>
    <startEvent id="start" name="开始"></startEvent>
    <endEvent id="end" name="结束"></endEvent>
    <userTask id="user_task1" name="写作业" activiti:assignee="${user}"></userTask>
    <userTask id="user_task2" name="打游戏" activiti:assignee="${user}"></userTask>
    <sequenceFlow id="sid-50EF2A93-83CE-44ED-AA41-F1A8F7ADE00C" sourceRef="start" targetRef="user_task1"></sequenceFlow>
    <sequenceFlow id="sid-5E51BC0F-5775-4727-8DD4-5325575BAC7B" sourceRef="user_task1" targetRef="user_task2"></sequenceFlow>
    <sequenceFlow id="sid-9CC4C5EC-9D5E-47F3-BEF4-94D268E004E0" sourceRef="user_task2" targetRef="end"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_activiti-test">
    <bpmndi:BPMNPlane bpmnElement="activiti-test" id="BPMNPlane_activiti-test">
      <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
        <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
        <omgdc:Bounds height="28.0" width="28.0" x="662.5" y="164.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="user_task1" id="BPMNShape_user_task1">
        <omgdc:Bounds height="80.0" width="100.0" x="236.5" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="user_task2" id="BPMNShape_user_task2">
        <omgdc:Bounds height="80.0" width="100.0" x="435.0" y="138.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-9CC4C5EC-9D5E-47F3-BEF4-94D268E004E0" id="BPMNEdge_sid-9CC4C5EC-9D5E-47F3-BEF4-94D268E004E0">
        <omgdi:waypoint x="535.0" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="662.5" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-5E51BC0F-5775-4727-8DD4-5325575BAC7B" id="BPMNEdge_sid-5E51BC0F-5775-4727-8DD4-5325575BAC7B">
        <omgdi:waypoint x="336.5" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="435.0" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-50EF2A93-83CE-44ED-AA41-F1A8F7ADE00C" id="BPMNEdge_sid-50EF2A93-83CE-44ED-AA41-F1A8F7ADE00C">
        <omgdi:waypoint x="130.0" y="178.0"></omgdi:waypoint>
        <omgdi:waypoint x="236.5" y="178.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

基本概念介绍

一个业务流程由以下几个部分组成:

  1. 事件(Events)

事件用来表明流程的生命周期中发生了什么事。事件总是画成一个圆圈, 在BPMN 2.0中事件有两大分类:

  • 捕获(Catching)事件。当流程执行到该事件, 它会中断执行,等待被触发
  • 抛出(Throwing))事件。当流程执行到该事件, 抛出一个结果

代表图形如下:

  1. 网关(Gateways) Gateway是BPMN2规范中的流程定义元素,中文可称为"网关"、"决策"、"判断"。网关用来控制流程的执行流向,当在拆分路径时产生令牌,在合并路径时消费令牌。常用网关可分为排他网关(XOR)、并行网关(AND)和包容网关(OR),代表图形如下:

  1. 活动(Activities)

活动(Activities)是业务流程定义的核心元素,中文可称为"活动"、"节点"、"步骤"。一个活动可以是流程中一个基本处理单元(如人工任务、服务任务),也可以是一个组合单元(如外部子流程、嵌套子流程),代表图形如下:

依赖

可能其他文章中还有一个依赖是activiti-spring-boot-starter-basic这两个区别不太了解,但是两个我都进行测试了,使用哪个都行。

这里不加security会报错,同时还要在启动类的@SpringBootApplication注解上排除两个类。

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-security</artifactId>
 </dependency>
 <dependency>
     <groupId>org.activiti</groupId>
     <artifactId>activiti-spring-boot-starter</artifactId>
     <version>7.1.0.M6</version>
 </dependency>
 <dependency>
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class})
public class SpringBootDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoApplication.class, args);
    }

}

配置数据库

由于数据还要存储在数据库中,还要在application.properties下配置数据库信息和activiti的信息。

spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&autoReconnect=true
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=h


spring.activiti.database-schema-update=true
spring.activiti.process-definition-location-prefix=classpath:/processes/

spring.activiti.db-history-used=true
spring.activiti.check-process-definitions=true
spring.activiti.history-level=audit


启动后会在数据库中生成非常多个表

控制器

package com.hxl.springbootdemo.activiti;


import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class ActivitiController {
    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    /**
     * 启动流程实例
     * @param userName
     * @return
     */
    @GetMapping("start")
    public String start(@RequestParam String userName){
        Map<String, Object> map = new HashMap<>();
        map.put("user", userName);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("activiti-test", map);
        return "OK";
    }

    /**
     * 获取任务
     * @param userName
     * @return
     */
    @GetMapping("tasks")
    public String tasks(@RequestParam String userName){
        List<Task> list = taskService.createTaskQuery().taskAssignee(userName).list();
        return list.toString();
    }

    /**
     * 完成任务
     * @param id 任务id
     * @return
     */
    @GetMapping("completetask")
    public String completeTask(@RequestParam String id) {
        taskService.complete(id);
        return "完成此任务";
    }

}

测试&结果

  1. http://localhost:8081/start?userName=小明 启动流程
OK
  1. http://localhost:8081/tasks?userName=小明 获取任务
[Task[id=b56be675-45b0-11eb-92b2-0242151ab6eb, name=写作业]]
  1. http://localhost:8081/completetask?id=b56be675-45b0-11eb-92b2-0242151ab6eb 完成任务
完成此任务
  1. http://localhost:8081/tasks?userName=小明 重新获取任务
[Task[id=cc3296b9-45b0-11eb-92b2-0242151ab6eb, name=打游戏]]

请假流程设计

好了,最后在设计一个简单的请假案例,先看一下图,在这个图中,第一步是用户提交请假信息,接着判断请假时长,如果大于等于3天,则走院长审批,如果小于3天,则走班任审批,这里用到了条件判断,添加条件可以在UI界面上点击指向线后在flow condition一栏中添加,这里就不说了。

<?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:activiti="http://activiti.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.activiti.org/processdef">
  <process id="activiti-leave" name="activiti-leave" isExecutable="true">
    <documentation>activiti-leave</documentation>
    <startEvent id="start" name="开始"></startEvent>
    <userTask id="user_task1" name="提交请假" activiti:assignee="#{user}">
      <extensionElements>
        <activiti:formProperty id="new_property_1" name="userName" type="string"></activiti:formProperty>
        <activiti:formProperty id="new_property_2" name="day" type="long"></activiti:formProperty>
        <activiti:formProperty id="new_property_3" name="tel" type="string"></activiti:formProperty>
        <activiti:formProperty id="new_property_4" name="content" type="string"></activiti:formProperty>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-055C2D31-C86C-4788-B373-D378575B98DC" sourceRef="start" targetRef="user_task1"></sequenceFlow>
    <userTask id="task_2" name="班主任审核" activiti:assignee="banren">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <exclusiveGateway id="sid-7230A3CF-B4DC-416F-AC22-21117F684115"></exclusiveGateway>
    <endEvent id="end" name="结束"></endEvent>
    <userTask id="task_3" name="院长" activiti:assignee="yuanzhang">
      <extensionElements>
        <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-31E21674-09F8-4AB8-8672-CF08043EDD21" sourceRef="user_task1" targetRef="sid-7230A3CF-B4DC-416F-AC22-21117F684115"></sequenceFlow>
    <sequenceFlow id="sid-D7DD5340-DE9B-4436-8F94-748A8933AC81" sourceRef="task_3" targetRef="end"></sequenceFlow>
    <sequenceFlow id="sid-45E0E489-E181-4EEC-B162-DE7F6747F5DB" sourceRef="task_2" targetRef="end"></sequenceFlow>
    <sequenceFlow id="sid-DDE1F19E-DC48-4797-8CDA-22261EF293D3" sourceRef="sid-7230A3CF-B4DC-416F-AC22-21117F684115" targetRef="task_3">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${day>=3}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="sid-D5171CDD-8C96-45F2-9E7B-34FF2683CEF0" sourceRef="sid-7230A3CF-B4DC-416F-AC22-21117F684115" targetRef="task_2">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${day<3}]]></conditionExpression>
    </sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_activiti-leave">
    <bpmndi:BPMNPlane bpmnElement="activiti-leave" id="BPMNPlane_activiti-leave">
      <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
        <omgdc:Bounds height="30.0" width="30.0" x="75.0" y="115.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="user_task1" id="BPMNShape_user_task1">
        <omgdc:Bounds height="80.0" width="100.0" x="171.5" y="90.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="task_2" id="BPMNShape_task_2">
        <omgdc:Bounds height="80.0" width="100.0" x="480.0" y="180.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-7230A3CF-B4DC-416F-AC22-21117F684115" id="BPMNShape_sid-7230A3CF-B4DC-416F-AC22-21117F684115">
        <omgdc:Bounds height="40.0" width="40.0" x="345.0" y="110.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
        <omgdc:Bounds height="28.0" width="28.0" x="660.0" y="116.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="task_3" id="BPMNShape_task_3">
        <omgdc:Bounds height="80.0" width="100.0" x="480.0" y="15.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-31E21674-09F8-4AB8-8672-CF08043EDD21" id="BPMNEdge_sid-31E21674-09F8-4AB8-8672-CF08043EDD21">
        <omgdi:waypoint x="271.5" y="130.0"></omgdi:waypoint>
        <omgdi:waypoint x="345.0" y="130.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-45E0E489-E181-4EEC-B162-DE7F6747F5DB" id="BPMNEdge_sid-45E0E489-E181-4EEC-B162-DE7F6747F5DB">
        <omgdi:waypoint x="580.0" y="188.75"></omgdi:waypoint>
        <omgdi:waypoint x="662.1280237439288" y="137.41998516004452"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-DDE1F19E-DC48-4797-8CDA-22261EF293D3" id="BPMNEdge_sid-DDE1F19E-DC48-4797-8CDA-22261EF293D3">
        <omgdi:waypoint x="379.2083333333333" y="124.20833333333333"></omgdi:waypoint>
        <omgdi:waypoint x="480.0" y="77.9483282674772"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-055C2D31-C86C-4788-B373-D378575B98DC" id="BPMNEdge_sid-055C2D31-C86C-4788-B373-D378575B98DC">
        <omgdi:waypoint x="105.0" y="130.0"></omgdi:waypoint>
        <omgdi:waypoint x="171.5" y="130.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-D5171CDD-8C96-45F2-9E7B-34FF2683CEF0" id="BPMNEdge_sid-D5171CDD-8C96-45F2-9E7B-34FF2683CEF0">
        <omgdi:waypoint x="377.8051181102362" y="137.1948818897638"></omgdi:waypoint>
        <omgdi:waypoint x="480.0" y="192.7963525835866"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-D7DD5340-DE9B-4436-8F94-748A8933AC81" id="BPMNEdge_sid-D7DD5340-DE9B-4436-8F94-748A8933AC81">
        <omgdi:waypoint x="580.0" y="81.04166666666667"></omgdi:waypoint>
        <omgdi:waypoint x="661.5832028216623" y="123.53291813628245"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

控制器

package com.hxl.springbootdemo.activiti;

import org.activiti.engine.HistoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@RestController
public class ActivitiLeaveController {
    private Map<String,String> map =new HashMap<>();
    @Autowired
    private TaskService taskService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    /**
     * 历史任务
     * @param userName
     * @return
     */
    @GetMapping("history")
    private  List<HistoricTaskInstance>  history(@RequestParam String  userName){
        List<HistoricTaskInstance> list1 = historyService.createHistoricTaskInstanceQuery().taskAssignee(userName).list();

        return  list1;
    }
    /**
     * 完成任务
     * @param id 任务id
     * @return
     */
    @GetMapping("completetask")
    public String completeTask(@RequestParam String id) {
        taskService.complete(id);
        return "完成此任务";
    }
    /**
     * 获取任务
     * @param userName
     * @return
     */
    @GetMapping("tasks")
    public List<Map<String,Object>> tasks(@RequestParam String userName){
        List<Map<String,Object>> result =new ArrayList<>();


        List<Task> list = taskService.createTaskQuery().taskAssignee(userName).list();
        for (Task task : list) {
            Map<String,Object> map =new HashMap<>();
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId())
                    .singleResult();
            Map<String, Object> variables = runtimeService.getVariables(processInstance.getId());
            map.put("请假天数",variables.get("day"));
            map.put("请假人",variables.get("user"));
            map.put("手机号",variables.get("tel"));
            map.put("内容",variables.get("content"));
            map.put("taskInfo",task.toString());
            result.add(map);
        }
        return result;
    }


    @PostMapping("leave")
    public String leave(@RequestParam String userName,
                        @RequestParam int day,
                        @RequestParam String tel,
                        @RequestParam String content) {
        Map<String, Object> objectObjectHashMap = new HashMap<>();
        objectObjectHashMap.put("user", userName);
        objectObjectHashMap.put("day", day);
        objectObjectHashMap.put("content",content);
        objectObjectHashMap.put("tel",tel);

        /**
         * 创建流程实例
         */
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("activiti-leave", objectObjectHashMap);

        runtimeService.setVariables(processInstance.getId(),objectObjectHashMap);


        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId())
                .singleResult();
        map.put(userName,processInstance.getId());
        System.out.println(task);
        taskService.complete(task.getId(),objectObjectHashMap);

        return "提交成功id=" + task.getId();
    }

}

测试&结果

1.http://localhost:8081/leave 提交信息

这里提交2个,一个小明请假1天,一个小张请假10天。

提交成功id=7ec509e1-45c8-11eb-8238-0242151ab6eb

2.http://localhost:8081/tasks?userName=banren 查看班任任务

由于小明请1天假,所以由班主任审核

[    {        "手机号": "15048879423",        "taskInfo": "Task[id=7ed42519-45c8-11eb-8238-0242151ab6eb, name=班主任审核]",        "请假人": "小明",        "内容": "a",        "请假天数": 1    }]

3.http://localhost:8081/completetask?id=7ed42519-45c8-11eb-8238-0242151ab6eb 班任完成审批

完成此任务

4.http://localhost:8081/tasks?userName=yuanzhang 查看院长任务

[    {        "手机号": "150xxxxxxxx",        "taskInfo": "Task[id=f2cf9cd0-45c8-11eb-8238-0242151ab6eb, name=院长]",        "请假人": "小张",        "内容": "娶媳妇",        "请假天数": 10    }]

5.http://localhost:8081/completetask?id=f2cf9cd0-45c8-11eb-8238-0242151ab6eb 院长完成审批

完成此任务
  1. http://localhost:8081/history?userName=小明查看历史
[
    {
        "id": "7ec509e1-45c8-11eb-8238-0242151ab6eb",
        "processInstanceId": "7ec298d9-45c8-11eb-8238-0242151ab6eb",
        "processDefinitionId": "activiti-leave:1:0d8b4a47-45c8-11eb-8238-0242151ab6eb",
        "startTime": "2020-12-24T09:14:58.755+00:00",
        "endTime": "2020-12-24T09:14:58.845+00:00",
        "durationInMillis": 90,
        "executionId": "7ec30e0e-45c8-11eb-8238-0242151ab6eb",
        "name": "提交请假",
        "assignee": "小明",
        "taskDefinitionKey": "user_task1",
        "priority": 50,
        "tenantId": "",
        "time": "2020-12-24T09:14:58.755+00:00",
        "createTime": "2020-12-24T09:14:58.755+00:00",
        "persistentState": {
            "taskDefinitionKey": "user_task1",
            "processDefinitionId": "activiti-leave:1:0d8b4a47-45c8-11eb-8238-0242151ab6eb",
            "durationInMillis": 90,
            "name": "提交请假",
            "assignee": "小明",
            "endTime": "2020-12-24T09:14:58.845+00:00",
            "priority": 50
        },
        "processVariables": {},
        "taskLocalVariables": {},
        "deleted": false,
        "inserted": false,
        "updated": false
    }
]