首頁>技術>

以前在圖書館看到過很多關於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>
基本概念介紹

一個業務流程由以下幾個部分組成:

事件(Events)

事件用來表明流程的生命週期中發生了什麼事。事件總是畫成一個圓圈, 在BPMN 2.0中事件有兩大分類:

捕獲(Catching)事件。當流程執行到該事件, 它會中斷執行,等待被觸發丟擲(Throwing))事件。當流程執行到該事件, 丟擲一個結果

代表圖形如下:

閘道器(Gateways)

Gateway是BPMN2規範中的流程定義元素,中文可稱為"閘道器"、"決策"、"判斷"。閘道器用來控制流程的執行流向,當在拆分路徑時產生令牌,在合併路徑時消費令牌。常用閘道器可分為排他閘道器(XOR)、並行閘道器(AND)和包容閘道器(OR),代表圖形如下:

活動(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=truespring.datasource.driver-class-name=com.mysql.jdbc.Driverspring.datasource.username=rootspring.datasource.password=hspring.activiti.database-schema-update=truespring.activiti.process-definition-location-prefix=classpath:/processes/spring.activiti.db-history-used=truespring.activiti.check-process-definitions=truespring.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;@RestControllerpublic 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 "完成此任務";    }}
測試&結果http://localhost:8081/start?userName=小明 啟動流程
OK
http://localhost:8081/tasks?userName=小明 獲取任務
[Task[id=b56be675-45b0-11eb-92b2-0242151ab6eb, name=寫作業]]
http://localhost:8081/completetask?id=b56be675-45b0-11eb-92b2-0242151ab6eb 完成任務
完成此任務
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;@RestControllerpublic 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 院長完成審批

完成此任務
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    }]

12
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 「類載入機制」類載入器剖析-類載入器速覽