欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot整合Flowable實現(xiàn)工作流的詳細流程

 更新時間:2025年06月16日 11:07:13   作者:程序員小假  
Flowable是一個使用Java編寫的輕量級業(yè)務流程引擎,Flowable流程引擎可用于部署B(yǎng)PMN2.0流程定義,創(chuàng)建這些流程定義的流程實例,進行查詢,訪問運行中或歷史的流程實例與相關(guān)數(shù)據(jù),本文給大家介紹了如何使用SpringBoot整合Flowable快速實現(xiàn)工作流,需要的朋友可以參考下

1、流程引擎介紹

Flowable 是一個使用 Java 編寫的輕量級業(yè)務流程引擎。Flowable 流程引擎可用于部署 BPMN2.0 流程定義(用于定義流程的行業(yè) XML 標準),創(chuàng)建這些流程定義的流程實例,進行查詢,訪問運行中或歷史的流程實例與相關(guān)數(shù)據(jù),等等。

Java 領(lǐng)域另一個流程引擎是 Activiti,不這兩個東西只要會使用其中一個,另一個就不在話下。
咱就不廢話了,上代碼吧。 

2、創(chuàng)建項目

首先創(chuàng)建一個 Spring Boot 項目,引入 Web、和 MySQL 驅(qū)動兩個依賴,如下圖:

項目創(chuàng)建成功之后,引入 flowable 依賴,如下:

<dependency>
    <groupId>org.flowable</groupId>
    <artifactId>flowable-spring-boot-starter</artifactId>
    <version>6.7.2</version>
</dependency>

這個會做一些自動化配置,默認情況下,所以位于 resources/processes 的流程都會被自動部署。
接下來在 application.yaml 中配置一下數(shù)據(jù)庫連接信息,當項目啟動的時候會自動初始化數(shù)據(jù)庫,將來流程引擎運行時候的數(shù)據(jù)會被自動持久化到數(shù)據(jù)庫中。

spring:
  datasource:
    username: root
    password: 123
    url: jdbc:mysql:///flowable?serverTimezone=Asia/Shanghai&useSSL=false

配置完成后,就可以啟動項目了。項目啟動成功之后,flowable 數(shù)據(jù)庫中就會自動創(chuàng)建如下這些表,將來流程引擎相關(guān)的數(shù)據(jù)都會自動保存到這些表中。
默認的表比較多,截圖只是其中一部分。

3、畫流程圖

畫流程圖算是比較有挑戰(zhàn)的一個步驟了,也是流程引擎使用的關(guān)鍵。官方提供了一些流程引擎繪制工具,感興趣的小伙伴可以自行去體驗;IDEA 也自帶了一個流程可視化的工具,但是特別難用。
這里說一下常用的 IDEA 插件 Flowable BPMN visualizer,如下圖:

裝好插件之后,在 resources 目錄下新建 processes 目錄,這個目錄下的流程文件將來會被自動部署。

接下來在 processes 目錄下,新建一個 BPMN 文件(插件裝好了就有這個選項了),如下:

來畫個請假的流程,就叫做 ask_for_leave.bpmn20.xml,注意最后面的 .bpmn20.xml 是固定后綴。
文件創(chuàng)建出來之后,右鍵單擊,選擇 View BPMN(Flowable) Diagram,就打開了可視化頁面了,就可以來繪制自己的流程圖了。

請假流程畫出來是這樣:

員工發(fā)起一個請假流程,首先是組長審核,組長審核通過了,就進入到經(jīng)理審核,經(jīng)理審核通過了,這個流程就結(jié)束了,如果組長審核未通過或者經(jīng)理審核未通過,則流程給員工發(fā)送一個請假失敗的通知,流程結(jié)束。

來看下這個流程對應的 XML 文件,一些流程細節(jié)會在 XML 文件中體現(xiàn)出來,如下:

<process id="ask_for_leave" name="ask_for_leave" isExecutable="true">
    <userTask id="leaveTask" name="請假" flowable:assignee="#{leaveTask}"/>
    <userTask id="zuzhangTask" name="組長審核" flowable:assignee="#{zuzhangTask}"/>
    <userTask id="managerTask" name="經(jīng)理審核" flowable:assignee="#{managerTask}"/>
    <exclusiveGateway id="managerJudgeTask"/>
    <exclusiveGateway id="zuzhangJudeTask"/>
    <endEvent id="endLeave" name="結(jié)束"/>
    <startEvent id="startLeave" name="開始"/>
    <sequenceFlow id="flowStart" sourceRef="startLeave" targetRef="leaveTask"/>
    <sequenceFlow id="modeFlow" sourceRef="leaveTask" targetRef="zuzhangTask"/>
    <sequenceFlow id="zuzhang_go" sourceRef="zuzhangJudeTask" targetRef="managerTask" name="通過">
        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='通過'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="zuzhang_reject" sourceRef="zuzhangJudeTask" targetRef="sendMail" name="拒絕">
        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='拒絕'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="jugdeFlow" sourceRef="managerTask" targetRef="managerJudgeTask"/>
    <sequenceFlow id="flowEnd" name="通過" sourceRef="managerJudgeTask" targetRef="endLeave">
        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='通過'}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="rejectFlow" name="拒絕" sourceRef="managerJudgeTask" targetRef="sendMail">
        <conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='拒絕'}]]></conditionExpression>
    </sequenceFlow>
    <serviceTask id="sendMail" flowable:exclusive="true" name="發(fā)送失敗提示" isForCompensation="true" flowable:class="org.javaboy.flowable.AskForLeaveFail"/>
    <sequenceFlow id="endFlow" sourceRef="sendMail" targetRef="askForLeaveFail"/>
    <endEvent id="askForLeaveFail" name="請假失敗"/>
    <sequenceFlow id="zuzhangTask_zuzhangJudeTask" sourceRef="zuzhangTask" targetRef="zuzhangJudeTask"/>
</process>

結(jié)合 XML 文件來解釋一下這里涉及到的 Flowable 中的組件:

  • <process> :表示一個完整的工作流程。
  • <startEvent> :工作流中起點位置,也就是圖中的綠色按鈕。
  • <endEvent> :工作流中結(jié)束位置,也就是圖中的紅色按鈕。
  • <userTask> :代表一個任務審核節(jié)點(組長、經(jīng)理等角色),這個節(jié)點上有一個 flowable:assignee 屬性,這表示這個節(jié)點該由誰來處理,將來在 Java 代碼中調(diào)用的時候,需要指定對應的處理人的 ID 或者其他唯一標記。
  • <serviceTask>:這是服務任務,在具體的實現(xiàn)中,這個任務可以做任何事情。
  • <exclusiveGateway> :邏輯判斷節(jié)點,相當于流程圖中的菱形框。
  • <sequenceFlow> :鏈接各個節(jié)點的線條,sourceRef 屬性表示線的起始節(jié)點,targetRef 屬性表示線指向的節(jié)點,圖中的線條都屬于這種。

流程圖這塊小編和大家稍微說一下,咋一看這個圖挺復雜很難畫,但是實際上只要認認真真去捋一捋這里邊的各個屬性,基本上很快就明白到底是怎么一回事。 

4、開發(fā)接口

接下來寫幾個接口,來體驗一把流程引擎。
在正式體驗之前,先來熟悉幾個類,這幾個類一會寫代碼會用到。 

4.1 Java 類梳理

ProcessDefinition

這個最好理解,就是流程的定義,也就相當于規(guī)范,每個 ProcessDefinition 都會有一個 id。 

ProcessInstance

這個就是流程的一個實例。簡單來說,ProcessDefinition 相當于是類,而 ProcessInstance 則相當于是根據(jù)類 new 出來的對象。 

Activity

Activity 是流程標準規(guī)范 BPMN2.0 里面的規(guī)范,流程中的每一個步驟都是一個 Activity。 

Execution

Execution 的含義是流程的執(zhí)行線路,通過 Execution 可以獲得當前 ProcessInstance 當前執(zhí)行到哪個 Activity了。 

Task

Task 就是當前要做的工作。

實際上這里涉及到的東西比較多,不過這里先整一個簡單的例子,所以上面這些知識點暫時夠用了。 

4.2 查看流程圖

在正式開始之前,先準備一個接口,用來查看流程圖的實時執(zhí)行情況,這樣方便查看流程到底執(zhí)行到哪一步了。
具體的代碼如下:

@RestController
public class HelloController {
    @Autowired
    RuntimeService runtimeService;
    @Autowired
    TaskService taskService;
    @Autowired
    RepositoryService repositoryService;
    @Autowired
    ProcessEngine processEngine;
    @GetMapping("/pic")
    public void showPic(HttpServletResponse resp, String processId) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        if (pi == null) {
            return;
        }
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(processId)
                .list();
        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, false);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = resp.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

這就一個工具,沒啥好說的,一會大家看完后面的代碼,再回過頭來看這個接口,很多地方就都懂了。 

4.3 開啟一個流程

為了方便,接下來的代碼都在單元測試中完成。

首先來開啟一個流程,代碼如下:

String staffId = "1000";
/**
 * 開啟一個流程
 */
@Test
void askForLeave() {
    HashMap<String, Object> map = new HashMap<>();
    map.put("leaveTask", staffId);
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("ask_for_leave", map);
    runtimeService.setVariable(processInstance.getId(), "name", "javaboy");
    runtimeService.setVariable(processInstance.getId(), "reason", "休息一下");
    runtimeService.setVariable(processInstance.getId(), "days", 10);
    logger.info("創(chuàng)建請假流程 processId:{}", processInstance.getId());
}

首先由員工發(fā)起一個請假流程,map 中存放的 leaveTask 是在 XML 流程文件中提前定義好的,提前定義好當前這個任務創(chuàng)建之后,該由誰來處理,這里是假設(shè)由工號為 1000 的員工來發(fā)起這樣一個請假流程。同時,還設(shè)置了一些額外信息。ask_for_leave 是在 XML 文件中定義的一個 process 的名稱。

好啦,現(xiàn)在執(zhí)行這個單元測試方法,執(zhí)行完成后,控制臺會打印出當前這個流程的 id,拿著這個 id 去訪問 4.2 小節(jié)的接口,結(jié)果如下:

可以看到,請假用紅色的框框起來了,說明當前流程走到了這一步。 

4.4 將請求提交給組長

接下來,就需要將這個請假流程向后推進一步,將請假事務提交給組長,代碼如下:

String zuzhangId = "90";
/**
 * 提交給組長審批
 */
@Test
void submitToZuzhang() {
    //員工查找到自己的任務,然后提交給組長審批
    List<Task> list = taskService.createTaskQuery().taskAssignee(staffId).orderByTaskId().desc().list();
    for (Task task : list) {
        logger.info("任務 ID:{};任務處理人:{};任務是否掛起:{}", task.getId(), task.getAssignee(), task.isSuspended());
        Map<String, Object> map = new HashMap<>();
        //提交給組長的時候,需要指定組長的 id
        map.put("zuzhangTask", zuzhangId);
        taskService.complete(task.getId(), map);
    }
}

首先利用 staffId 查找到當前員工的 id,進而找到當前員工需要執(zhí)行的任務,遍歷這個任務,調(diào)用 taskService.complete 方法將任務提交給組長,注意在 map 中指定組長的 id。
提交完成后,再去看流程圖片,如下:

可以看到,流程圖走到組長審批了。 

4.5 組長審批

組長現(xiàn)在有兩種選擇,同意或者拒絕,同意的代碼如下:

/**
 * 組長審批-批準
 */
@Test
void zuZhangApprove() {
    List<Task> list = taskService.createTaskQuery().taskAssignee(zuzhangId).orderByTaskId().desc().list();
    for (Task task : list) {
        logger.info("組長 {} 在審批 {} 任務", task.getAssignee(), task.getId());
        Map<String, Object> map = new HashMap<>();
        //組長審批的時候,如果是同意,需要指定經(jīng)理的 id
        map.put("managerTask", managerId);
        map.put("checkResult", "通過");
        taskService.complete(task.getId(), map);
    }
}

通過組長的 id 查詢組長的任務,同意的話,需要指定經(jīng)理,也就是這個流程下一步該由誰來處理。
拒絕的代碼如下:

/**
 * 組長審批-拒絕
 */
@Test
void zuZhangReject() {
    List<Task> list = taskService.createTaskQuery().taskAssignee(zuzhangId).orderByTaskId().desc().list();
    for (Task task : list) {
        logger.info("組長 {} 在審批 {} 任務", task.getAssignee(), task.getId());
        Map<String, Object> map = new HashMap<>();
        //組長審批的時候,如果是拒絕,就不需要指定經(jīng)理的 id
        map.put("checkResult", "拒絕");
        taskService.complete(task.getId(), map);
    }
}

拒絕的話,就沒那么多事了,直接設(shè)置 checkResult 為拒絕即可。

假設(shè)這里執(zhí)行了同意,那么流程圖如下:

4.6 經(jīng)理審批

經(jīng)理審批和組長審批差不多,只不過經(jīng)理這里是最后一步了,不需要再指定下一位處理人了,同意的代碼如下:

/**
 * 經(jīng)理審批自己的任務-批準
 */
@Test
void managerApprove() {
    List<Task> list = taskService.createTaskQuery().taskAssignee(managerId).orderByTaskId().desc().list();
    for (Task task : list) {
        logger.info("經(jīng)理 {} 在審批 {} 任務", task.getAssignee(), task.getId());
        Map<String, Object> map = new HashMap<>();
        map.put("checkResult", "通過");
        taskService.complete(task.getId(), map);
    }
}

拒絕代碼如下:

/**
 * 經(jīng)理審批自己的任務-拒絕
 */
@Test
void managerReject() {
    List<Task> list = taskService.createTaskQuery().taskAssignee(managerId).orderByTaskId().desc().list();
    for (Task task : list) {
        logger.info("經(jīng)理 {} 在審批 {} 任務", task.getAssignee(), task.getId());
        Map<String, Object> map = new HashMap<>();
        map.put("checkResult", "拒絕");
        taskService.complete(task.getId(), map);
    }
}

4.7 拒絕流程

如果組長拒絕了或者經(jīng)理拒絕了,也有相應的處理方案,首先在 XML 流程文件定義時,如下:

<serviceTask id="sendMail" flowable:exclusive="true" name="發(fā)送失敗提示" isForCompensation="true" flowable:class="org.javaboy.flowable.AskForLeaveFail"/>

如果請假被拒絕,會進入到這個 serviceTask,serviceTask 對應的處理類是 org.javaboy.flowable.AskForLeaveFail,該類的代碼如下:

public class AskForLeaveFail implements JavaDelegate {
    @Override
    public void execute(DelegateExecution execution) {
        System.out.println("請假失敗。。。");
    }
}

也就是請假失敗會進入到這個方法中,現(xiàn)在就可以在這個方法中該干嘛干嘛了。

以上就是SpringBoot整合Flowable實現(xiàn)工作流的詳細流程的詳細內(nèi)容,更多關(guān)于SpringBoot Flowable工作流的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java多線程編程技術(shù)詳解和實例代碼

    java多線程編程技術(shù)詳解和實例代碼

    這篇文章主要介紹了 java多線程編程技術(shù)詳解和實例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • java判斷是否空最簡單的方法

    java判斷是否空最簡單的方法

    在本篇文章里小編給大家整理的一篇關(guān)于java判斷是否空最簡單的方法,有興趣的讀者們可以參考下。
    2019-12-12
  • java中如何執(zhí)行xshell命令

    java中如何執(zhí)行xshell命令

    這篇文章主要介紹了java中如何執(zhí)行xshell命令,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java實現(xiàn)List反轉(zhuǎn)的方法總結(jié)

    Java實現(xiàn)List反轉(zhuǎn)的方法總結(jié)

    在Java中,反轉(zhuǎn)一個List意味著將其元素的順序顛倒,使得第一個元素變成最后一個,最后一個元素變成第一個,依此類推,這一操作在處理數(shù)據(jù)集合時非常有用,所以本文給大家總結(jié)了Java實現(xiàn)List反轉(zhuǎn)的方法,需要的朋友可以參考下
    2024-04-04
  • Java如何獲取JSON中某個對象的值

    Java如何獲取JSON中某個對象的值

    這篇文章主要介紹了Java如何獲取JSON中某個對象的值,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Windows安裝Maven并配置環(huán)境的詳細步驟

    Windows安裝Maven并配置環(huán)境的詳細步驟

    Maven是一個非常流行的構(gòu)建和項目管理工具,用于Java開發(fā),它提供了一個強大的依賴管理系統(tǒng)和一系列標準化的構(gòu)建生命周期,本文將指導您如何在Windows操作系統(tǒng)上安裝和配置Maven,需要的朋友可以參考下
    2023-05-05
  • ssm?mybatis如何配置多個mapper目錄

    ssm?mybatis如何配置多個mapper目錄

    這篇文章主要介紹了ssm?mybatis如何配置多個mapper目錄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教。
    2022-01-01
  • Springboot 使用 maven-resources-plugin 打包變量替換jar沒有打包進去、Jar包沒有被使用的解決方法

    Springboot 使用 maven-resources-plugin 打包變量替換ja

    這篇文章主要介紹了Springboot 使用 maven-resources-plugin 打包變量替換jar沒有打包進去、Jar包沒有被使用的解決方法,本文給大家介紹的非常詳細,感興趣的朋友一起看看吧
    2024-08-08
  • Spring Cloud Stream簡單用法

    Spring Cloud Stream簡單用法

    Spring cloud stream是為構(gòu)建微服務消息驅(qū)動而產(chǎn)生的一種框架。Spring Cloud Stream基于Spring boot的基礎(chǔ)上,可創(chuàng)建獨立的、生產(chǎn)級別的Spring應用,并采用Spring Integration來連接消息中間件提供消息事件驅(qū)動,一起看看吧
    2021-07-07
  • SpringBoot整合Spring Data Elasticsearch的過程詳解

    SpringBoot整合Spring Data Elasticsearch的過程詳解

    這篇文章主要介紹了SpringBoot整合Spring Data Elasticsearch的過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09

最新評論