【Activiti工作流】(四)Activiti之流程網關——實現創業擔保貸款審批流程

筆者認爲,Activiti作爲一個應用框架,涉及了比較多的概念,如果一個個的闡述概念細節,一方面比較枯燥,另一方面讀者也容易雲裏霧裏。本節開始,筆者會從實際的應用案例出發,來帶漸進的學習Activiti的知識,通過項目驅動知識的學習。

一、創業擔保貸款業務審批流程建模

1、創業擔保貸款簡介

創業擔保貸款是國家推出的一項惠民政策性貸款,通過政府出資設立擔保基金,以人社部門擔保、金融機構發放貸款、財政部門補貼利息的方式運行,旨在解決自謀職業、自主創業者在創業初期自籌資金不足的問題。以上是官方的定義,我們來通俗的瞭解下,創業擔保貸款政策俗稱“創業貸款”,不管你是大學畢業生,還是下崗的失業人員,總之,如果想去創業,比如開個科技公司,如果遇到資金不足的問題,可以去屬地的人社部門申請這項貸款,這項貸款最大的亮點是國家補貼利息,比如你申請了30萬的創業貸款,貸款期滿2年後只需還款30萬即可,不用額外付利息。如果各位學有所成,想開一家公司,這項政策你值得考慮。

2、業務流程建模

創業擔保貸款的審批流程涉及多個部門,我們首先來看最終的業務模型圖,然後來做具體的業務流程做詳細解釋。
在這裏插入圖片描述
大家不懂圖中的一些概念沒關係,下面詳細解釋,首先需要創業者發起創業擔保貸款的申請,在實際審批中,需要區級的就業部門和金融機構的信貸員同時對創業者的個人信息進行審批,區級就業部門審覈創業者的社保信息,金融機構審覈創業者的徵信信息(納入徵信黑名單的老賴是不可以申請的),也就是說這兩個部門的審批是併發進行的,在Activiti中,我們用並行網關(parallel Gateway)來表示流程的併發執行,也就是圖中用紅色圈標註的①②(注意①②③④⑤是筆者後期爲了描述方便從畫圖工具繪製的符號,而不是BPMN的元素符號),從①的並行網關引出(官方稱爲分岔,英文單詞爲fork)兩條執行流程,之後在②出合併(join)。之後流程走到符號③的位置,在實際的審批過程中,“【區就業部門】審批社保信息”和“【金融機構】審批徵信信息”會有審覈不通過的情況,比如我們剛纔說的,如果創業者的徵信信息不通過,那麼他是不可以申請的,也就是不能走下面的審批流程。如果他的個人信息經過“區就業部門”和“金融機構”審批都沒有問題的話,纔可以進入下一個審覈環節。所以在Activiti流程圖中,我們用排他網關(Exclusive Gateway)來表示“接下來的路,我只能選擇一條來執行”。只有“全部審覈通過”纔可以進入下一流程,如果存在一家單位審覈不通過,則流程進入結束事件。而走哪條路,則是需要在路徑上(也就是圖中的箭頭)設定條件的,這個我們下面會說。
在闡述下面的流程之前,我們總結下並行網關和排他網關,並行網關可以讓我們並行的執行多條路徑,而排他網關可以讓我們通過在路徑上設置條件來決定流程的走向,但是,排他網關最終只允許走一條路徑,也就是說如果在排他網關的多個路徑上我們設置了條件,如果這些條件都爲“true”,那麼只會默認執行第一個值爲“true”的路徑其他的路徑上雖然值都爲true,但都會忽略。那麼如何將並行網關和排他網關進行結合呢,也就是既能執行多條路徑,又能在路徑上設置條件來控制路徑的執行呢。答案就是下面我們要說的包容網關(inclusive gateway)
我們繼續我們的業務流程,流程節點走到④。現實的業務場景是,創業擔保貸款申請人可以是個人(最高貸款額度爲50)和公司(最高貸款額度爲300萬),無論是個人還是公司,都需要市級就業部門和金融機構的審批,但如果是公司,需要市級財政部門的審批,市級財政部門不對個人進行審批。這就需要我們在路徑上設置多個執行條件,運行走多條路徑。所以我們在④出設置包容網關的開始,引出三條執行路徑,並在路徑上設置執行條件(注意:圖中的文字並不是設置執行條件的方式,我們今後會具體說明如何設置),根據實際情況決定執行路徑,最後在⑤處合併,進入下一個任務節點。
“計算貸款額度”該任務和以前我們學到的任務不太一樣。此處的任務是一個服務任務“ServiceTask”,它不同於用戶任務(用戶任務需要用戶手動去完成),服務任務是自動完成的,具體的使用方式我們下面會講到。

二、業務流程模型圖的配置方法

上面我們只是簡簡單單的梳理了創業擔保貸款業務審批流程圖,並介紹了網關的一些基本概念,但是業務流程圖內對各個活動節點的配置還從未涉及,其實這一部分是非常重要的。下面開始詳述

1、啓動事件中initiator屬性的配置與使用

我們再把目光轉移到業務流程的開頭,我們思考一個問題,當要啓動一次流程實例的時候,是誰在啓動,在helloWorld的Demo中,我們自己以手動的方式通過如下代碼啓動了流程實例:

 ProcessInstance processInstance1 = runtimeService.startProcessInstanceByKey("studentLeaveProcess");

之後就看到了xialuo同學的賬戶中存在了待辦任務。在實際應用中,通常都是由用戶自己來啓動流程實例。Activiti在startEvent上擴展了一個屬性activiti:initiator用來記錄流程的發起者。我們在activiti的eclipse插件中看下這個activiti:initiator的配置:
在這裏插入圖片描述
我們在啓動事件->MainConfig->initiator中定義了一個字符串,這個字符串的名字可以任意起名字,它本質上是一個流程變量,initiator需要配合如下方法使用:

identityService.setAuthenticatedUserId(userAccount);

identityService(身份服務)是Activiti的七大服務組件之一,調用上述方法後,方法會將userAccount(userAccount爲當前登錄賬戶的賬號,一般系統都要求只有登錄後才允許發起流程,不允許匿名用戶隨便發起一次流程實例)中的值設定到applyUserId中用來記錄流程流程的發起者,而這個變量applyUserId在一次流程實例的審批過程中是一直存在的,可以供後續流程來獲取這個變量進行使用。至於initiator其他的應用場景,這裏推薦一篇博文給大家。

2、【創業者】申請-用戶任務的配置

啓動流程實例後,流程走到【創業者】申請這個用戶任務上,首先看如下圖:
在這裏插入圖片描述
對於當前用戶任務,general中只配置Name(任務名稱),這個任務id筆者建議大家一定要使用英文並且和Name屬性屬性,方便日後的調式,筆者在這裏使用“EntrepreneurApply”,接着我們看General下面的下一個選顯卡Main config。
在這裏插入圖片描述
這裏最重要的屬性當屬“Assignee”了即任務的辦理人,在helloWorld的demo中,我們是直接將其寫死的,粗暴的把整個請假流程只給了xialuo夏洛同學用,當然此處你可以指定給任何人,只需要把他的賬戶寫上去就行了,但是在當前這個用戶任務中,我們是給所有的創業者準備的,也就是說我們需要準備一個變量來表示創者者這個羣體,當前登錄的用戶是誰,我們就把當前用戶的賬號賦值給這個變量不就行了麼。所以在Assignee這個屬性中,可以通過如下的方式來定義一個流程中的變量:

${Entrepreneur}

也就是我們起了一個叫Entrepreneur的變量來表示創業者。這樣做是完全沒有問題,但是我們要優化一下,還記得我們在啓動事件中通過initiator屬性定義了applyUserId變量(注意在initiator屬性中直接寫入變量名稱即可,不需要${applyUserId}表示)來存放流程的發起者,而在實際業務中,流程的發起者其實也就創業者自己,與【創業者】申請這個任務的辦理人是同一個人,所以我們在【創業者】申請這個任務中將Assignee這樣定義:

${applyUserId}

剛剛提到applyUserId是一個流程變量,也就是在整個流程實例中都是存在的,既然已經在啓動事件中定義好了流程變量applyUserId,在【創業者】申請這個任務的applyUserIdapplyUserId{applyUserId}表示直接引用applyUserId中的值。如果採用{Entrepreneur}的方式定義,需要額外再賦值給它。
之後我們可以趁熱打鐵。把餘下的用戶任務的Assignee也配置好,對應如下。
【區就業部門】審批社保信息:districtJiuYe
【金融機構】審批徵信信息:bank
【市級就業】實地考察:shiJiuYe
【金融機構】實地考察:bank
【市級財政】實地考察:finance

3、監聽器的使用

接下來的流程走到了一個並行網關分岔出兩條執行路徑,這兩條路徑是並行的,在並行網關的合併出,也就是②這個網關處,如何決定接下來的執行路徑呢,我們知道接下來的排他網關只可以有一條路徑可以執行,而且執行哪一條路徑是由【區就業部門】審批社保信息以及【金融機構】審批徵信信息的審批結果決定的。所以我們在並行網關②中通過一個監聽器來彙總兩家單位的審批結果。
在這裏插入圖片描述
選中②處的並行網關,按照圖中的順序即可彈出監聽器的配置界面,我們重點看Type這個屬性,監聽器的配置方式有多種,常用的有Java class和Delegate expression的方式。通過Java類的方式指定一個具體的Java類作爲監聽器,然後在這個類中實現相應的內容。Delegate expression的方式可以指定一定spring容器的bean來完成監聽功能,此處我們選取Delegate expression的方式。如下表示,之後點擊ok確定。
在這裏插入圖片描述
此處我們僅僅是取了一個監聽器的名字而已,具體的實現需要在項目中新建名稱爲CollectInformationCheckResult的類,然後實現JavaDelegate類,並通過spring註解(當然其他方式也可以)的方式使該類成爲一個bean。首先給出該類的基本模式然後再給出具體的實現邏輯:

@Service("CollectInformationCheckResult")
public class CollectInformationCheckResult implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) {
        
    }
}

在給出具體的業務實現前,我們添加一個小小的知識點

helloWorld案例中,我們給出了完成用戶任務的最簡單方式:
taskService.complete(String taskId);
其實taskService.complete()有很多重載的方法,比如下面這個:
void complete(String taskId, Map<String, Object> var2);
當前方法允許我們在完成任務的時候,同時傳入一個map來設定流程變量,我們通過實例來表示,例如【區就業部門】審批社保信息後,一定會給出一個最終的審批結果,我們就可以把這個結果存儲在一個map中,然後傳給complete方法,Activiti會在完成任務的時候將map中的內容轉換爲流程變量,供後續流程使用,代碼如下:
HashMap<String, String> map = new HashMap<>();
map.put("districtJiuYeAgree","true");
taskService.complete(taskId,map);

下面我們開始實現監聽器的具體業務邏輯:

@Service("CollectInformationCheckResult")
public class CollectInformationCheckResult implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) {
        //獲取區就業的審批意見
        String districtJiuYeAgree =(String)delegateExecution.getVariable("districtJiuYeAgree");
        //獲取金融機構的審批意見
        String bankAgree =(String)delegateExecution.getVariable("bankAgree");
        //設定控制流程走向的參數
        if ("true".equals(districtJiuYeAgree)&&"true".equals(bankAgree)){
            delegateExecution.setVariable("GuaranteeAndCreditApproved","true");
        }else {
            delegateExecution.setVariable("GuaranteeAndCreditApproved","false");
        }
    }
}

首先看如下方法

void execute(DelegateExecution delegateExecution)

該方法的參數傳入了DelegateExecution 對象,也就是當前執行流的具體信息,我們可以通過DelegateExecution中的方法來獲取當前流程實例中的信息,

delegateExecution.getVariable("districtJiuYeAgree")

該方法正是獲取上一個活動節點中,區就業部門對信息作出的審批結果。同理金融機構的審批意見也可以獲得。最終將以上兩個單位的最終審批結果通過如下代碼設定到了流程變量中,供後續節點使用

delegateExecution.setVariable("GuaranteeAndCreditApproved","true");

4、在排他網關上設置執行條件

我們知道經過並行網關設置的監聽器最終會產生一個流程變量GuaranteeAndCreditApproved,這個流程變量的值或者爲‘true’或者爲‘false’,而這個值將會決定後續的流程走向,我們執行把滿足這兩個值得條件設置到排他網關引出的兩條箭頭上即可。設置如下main config->Condition
在這裏插入圖片描述
在這裏插入圖片描述

4、在包容網關中設置執行條件

上一部分我們學習瞭如何在排他網關的執行路徑中設置執行條件。本部分我們就學習如何在包容網關中設置執行條件。設置條件的方式其實與方纔學習的是一樣。但要注意的是,包容網關中設置了執行條件,只要滿足條件,本條路徑就會執行。我們還是通過這個業務場景來分析。創業者在申請創業擔保貸款時,系統(我們自己的app應用)會將創業的主體類型存儲到一個流程變量applicantType中,0代表主體是個人,1代表主體是公司。我們直接看包容網關中對條件的設置:
在這裏插入圖片描述
第二條線的設置與上述一樣。
在這裏插入圖片描述
條件設置完畢後,當流程走到這個包容網關,就判斷此時applicantType流程變量中的值,如果該值爲0,那麼第一條與第二條執行路徑就會創建,第三條不會創建。如果applicantType=1,那麼第一條、跌條、第三條執行路徑就都會被創建。然後進行相應業務邏輯的處理
【市級就業】實地考察,【金融機構】實地考察,【市級財政】實地考察這三個用戶主要是用來對創業者貸款額度進行授信,每家單位根據考察的實際情況給出他們認定的貸款額度。最後完成當前任務並把這個貸款額度存到一個流程變量中。

5、通過服務任務計算貸款額度

流程走到最後一步“計算貸款額度”,實際中的業務操作爲,通過計算包容網關中審批單位給出的貸款額度,求取平均值最終確定創業者的貸款額度。這項工作在實際應用中往往由市級就業部門來完成。但本質上這個計算的工作是不需要人爲的去操作。直接通過Activiti的服務任務就可以完成。
【服務任務】ServiceTask是不需要人爲去操作的,只需要通過服務任務指定的監聽器就可以完成。監聽器的設定方式和我們方纔想學習的並行網關中監聽器的設置是一樣的。我們同樣是以代理表達式的方式設定。具體的業務邏輯實現大家可以參考小3部分的內容自己實現下。
至此我們配置完畢。下面給出業務流程圖的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/test">
  <process id="EGApproval" name="EGApproval" isExecutable="true">
    <startEvent id="startevent1" name="Start" activiti:initiator="applyUserId"></startEvent>
    <endEvent id="endevent1" name="End"></endEvent>
    <userTask id="districtJiuYeCheck" name="【區就業部門】審批社保信息" activiti:assignee="districtJiuYe"></userTask>
    <userTask id="bankCheck" name="【金融機構】審批徵信信息" activiti:assignee="bank"></userTask>
    <userTask id="EntrepreneurApply" name="【創業者】申請" activiti:assignee="${applyUserId}"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="EntrepreneurApply"></sequenceFlow>
    <userTask id="shiJiuYeInvestigation" name="【市級就業】實地考察" activiti:assignee="shiJiuYe"></userTask>
    <parallelGateway id="parallelgateway1" name="Parallel Gateway"></parallelGateway>
    <sequenceFlow id="flow2" sourceRef="EntrepreneurApply" targetRef="parallelgateway1"></sequenceFlow>
    <parallelGateway id="parallelgateway2" name="Parallel Gateway">
      <extensionElements>
        <activiti:executionListener event="start" delegateExpression="${CollectInformationCheckResult}"></activiti:executionListener>
      </extensionElements>
    </parallelGateway>
    <sequenceFlow id="flow5" sourceRef="districtJiuYeCheck" targetRef="parallelgateway2"></sequenceFlow>
    <sequenceFlow id="flow6" sourceRef="bankCheck" targetRef="parallelgateway2"></sequenceFlow>
    <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
    <sequenceFlow id="flow7" sourceRef="parallelgateway2" targetRef="exclusivegateway1"></sequenceFlow>
    <userTask id="bankInvestigation" name="【金融機構】實地考察" activiti:assignee="bank"></userTask>
    <userTask id="financeInvestigation" name="【市級財政】實地考察" activiti:assignee="finance"></userTask>
    <inclusiveGateway id="inclusivegateway1" name="Inclusive Gateway"></inclusiveGateway>
    <sequenceFlow id="flow8" name="全部通過" sourceRef="exclusivegateway1" targetRef="inclusivegateway1">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${GuaranteeAndCreditApproved==true}]]></conditionExpression>
    </sequenceFlow>
    <endEvent id="endevent3" name="End"></endEvent>
    <sequenceFlow id="flow9" name="非全部通過" sourceRef="exclusivegateway1" targetRef="endevent3">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${GuaranteeAndCreditApproved==false}]]></conditionExpression>
    </sequenceFlow>
    <inclusiveGateway id="inclusivegateway2" name="Inclusive Gateway"></inclusiveGateway>
    <sequenceFlow id="flow13" sourceRef="shiJiuYeInvestigation" targetRef="inclusivegateway2"></sequenceFlow>
    <sequenceFlow id="flow14" sourceRef="bankInvestigation" targetRef="inclusivegateway2"></sequenceFlow>
    <sequenceFlow id="flow15" sourceRef="financeInvestigation" targetRef="inclusivegateway2"></sequenceFlow>
    <sequenceFlow id="flow17" sourceRef="parallelgateway1" targetRef="districtJiuYeCheck"></sequenceFlow>
    <sequenceFlow id="flow18" sourceRef="parallelgateway1" targetRef="bankCheck"></sequenceFlow>
    <sequenceFlow id="flow19" name="創業主體爲個人或公司" sourceRef="inclusivegateway1" targetRef="shiJiuYeInvestigation">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${applicantType==0||applicantType==1}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow20" name="創業主體爲公司" sourceRef="inclusivegateway1" targetRef="financeInvestigation">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${applicantType==1}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow21" name="創業主體爲個人或公司" sourceRef="inclusivegateway1" targetRef="bankInvestigation">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${applicantType==0||applicantType==1}]]></conditionExpression>
    </sequenceFlow>
    <serviceTask id="servicetask1" name="計算貸款額度" activiti:delegateExpression="${CalculateLoanAmount}"></serviceTask>
    <sequenceFlow id="flow22" sourceRef="inclusivegateway2" targetRef="servicetask1"></sequenceFlow>
    <sequenceFlow id="flow23" sourceRef="servicetask1" targetRef="endevent1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_EGApproval">
    <bpmndi:BPMNPlane bpmnElement="EGApproval" id="BPMNPlane_EGApproval">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="80.0" y="240.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="1200.0" y="240.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="districtJiuYeCheck" id="BPMNShape_districtJiuYeCheck">
        <omgdc:Bounds height="61.0" width="121.0" x="380.0" y="176.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="bankCheck" id="BPMNShape_bankCheck">
        <omgdc:Bounds height="55.0" width="111.0" x="380.0" y="284.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="EntrepreneurApply" id="BPMNShape_EntrepreneurApply">
        <omgdc:Bounds height="55.0" width="105.0" x="160.0" y="230.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="shiJiuYeInvestigation" id="BPMNShape_shiJiuYeInvestigation">
        <omgdc:Bounds height="55.0" width="105.0" x="829.0" y="140.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="parallelgateway1" id="BPMNShape_parallelgateway1">
        <omgdc:Bounds height="40.0" width="40.0" x="302.0" y="237.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="parallelgateway2" id="BPMNShape_parallelgateway2">
        <omgdc:Bounds height="40.0" width="40.0" x="520.0" y="237.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1">
        <omgdc:Bounds height="40.0" width="40.0" x="580.0" y="237.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="bankInvestigation" id="BPMNShape_bankInvestigation">
        <omgdc:Bounds height="55.0" width="105.0" x="829.0" y="230.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="financeInvestigation" id="BPMNShape_financeInvestigation">
        <omgdc:Bounds height="55.0" width="105.0" x="829.0" y="320.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="inclusivegateway1" id="BPMNShape_inclusivegateway1">
        <omgdc:Bounds height="40.0" width="40.0" x="680.0" y="237.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent3" id="BPMNShape_endevent3">
        <omgdc:Bounds height="35.0" width="35.0" x="583.0" y="360.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="inclusivegateway2" id="BPMNShape_inclusivegateway2">
        <omgdc:Bounds height="40.0" width="40.0" x="990.0" y="237.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="servicetask1" id="BPMNShape_servicetask1">
        <omgdc:Bounds height="55.0" width="105.0" x="1060.0" y="230.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="115.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="160.0" y="257.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="265.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="302.0" y="257.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
        <omgdi:waypoint x="501.0" y="206.0"></omgdi:waypoint>
        <omgdi:waypoint x="540.0" y="206.0"></omgdi:waypoint>
        <omgdi:waypoint x="540.0" y="237.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
        <omgdi:waypoint x="491.0" y="311.0"></omgdi:waypoint>
        <omgdi:waypoint x="540.0" y="311.0"></omgdi:waypoint>
        <omgdi:waypoint x="540.0" y="277.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
        <omgdi:waypoint x="560.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="580.0" y="257.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
        <omgdi:waypoint x="620.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="680.0" y="257.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="14.0" width="48.0" x="609.0" y="237.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">
        <omgdi:waypoint x="600.0" y="277.0"></omgdi:waypoint>
        <omgdi:waypoint x="600.0" y="360.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="14.0" width="60.0" x="540.0" y="319.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow13" id="BPMNEdge_flow13">
        <omgdi:waypoint x="934.0" y="167.0"></omgdi:waypoint>
        <omgdi:waypoint x="1010.0" y="167.0"></omgdi:waypoint>
        <omgdi:waypoint x="1010.0" y="237.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow14" id="BPMNEdge_flow14">
        <omgdi:waypoint x="934.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="990.0" y="257.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow15" id="BPMNEdge_flow15">
        <omgdi:waypoint x="934.0" y="347.0"></omgdi:waypoint>
        <omgdi:waypoint x="979.0" y="347.0"></omgdi:waypoint>
        <omgdi:waypoint x="1010.0" y="347.0"></omgdi:waypoint>
        <omgdi:waypoint x="1010.0" y="277.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow17" id="BPMNEdge_flow17">
        <omgdi:waypoint x="322.0" y="237.0"></omgdi:waypoint>
        <omgdi:waypoint x="322.0" y="206.0"></omgdi:waypoint>
        <omgdi:waypoint x="380.0" y="206.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow18" id="BPMNEdge_flow18">
        <omgdi:waypoint x="322.0" y="277.0"></omgdi:waypoint>
        <omgdi:waypoint x="322.0" y="311.0"></omgdi:waypoint>
        <omgdi:waypoint x="380.0" y="311.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow19" id="BPMNEdge_flow19">
        <omgdi:waypoint x="700.0" y="237.0"></omgdi:waypoint>
        <omgdi:waypoint x="700.0" y="167.0"></omgdi:waypoint>
        <omgdi:waypoint x="829.0" y="167.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="42.0" width="100.0" x="720.0" y="127.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow20" id="BPMNEdge_flow20">
        <omgdi:waypoint x="700.0" y="277.0"></omgdi:waypoint>
        <omgdi:waypoint x="700.0" y="347.0"></omgdi:waypoint>
        <omgdi:waypoint x="829.0" y="347.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="14.0" width="84.0" x="720.0" y="324.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow21" id="BPMNEdge_flow21">
        <omgdi:waypoint x="720.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="829.0" y="257.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="42.0" width="100.0" x="719.0" y="223.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow22" id="BPMNEdge_flow22">
        <omgdi:waypoint x="1030.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="1060.0" y="257.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow23" id="BPMNEdge_flow23">
        <omgdi:waypoint x="1165.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="1200.0" y="257.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

三、使用Springboot整合activiti

現在開始我們學校將springboot與Activiti進行整合,需要配置以下幾個內容
1、application.yml配置文件

server:
  port: 8080
spring:
  datasource:
    url:  jdbc:mysql://localhost:3306/activitistudy?setUnicode=true&characterEncoding=utf8
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

2、Activiti的配置類

package com.cydk.controller;

import org.activiti.engine.*;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.io.IOException;

@Configuration
public class ActivitiConfiguration {

    @javax.annotation.Resource
    private DataSource dataSource;
    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Bean
    public SpringProcessEngineConfiguration springProcessEngineConfiguration(){
        SpringProcessEngineConfiguration spec = new SpringProcessEngineConfiguration();
        spec.setDataSource(dataSource);
        spec.setTransactionManager(platformTransactionManager);
        spec.setDatabaseSchemaUpdate("true");
        Resource[] resources = null;
        // 啓動自動部署流程
        try {
            resources = new PathMatchingResourcePatternResolver().getResources("classpath*:bpmn/*.bpmn");
        } catch (IOException e) {
            e.printStackTrace();
        }
        spec.setDeploymentResources(resources);
        return spec;
    }

    @Bean
    public ProcessEngineFactoryBean processEngine(){
        ProcessEngineFactoryBean processEngineFactoryBean = new ProcessEngineFactoryBean();
        processEngineFactoryBean.setProcessEngineConfiguration(springProcessEngineConfiguration());
        return processEngineFactoryBean;
    }


    @Bean
    public RepositoryService repositoryService() throws Exception{
        return processEngine().getObject().getRepositoryService();
    }
    @Bean
    public RuntimeService runtimeService() throws Exception{
        return processEngine().getObject().getRuntimeService();
    }
    @Bean
    public TaskService taskService() throws Exception{
        return processEngine().getObject().getTaskService();
    }
    @Bean
    public HistoryService historyService() throws Exception{
        return processEngine().getObject().getHistoryService();
    }
    @Bean
    public IdentityService identityService() throws Exception{
        return processEngine().getObject().getIdentityService();
    }

    @Bean
    public ManagementService managementService() throws Exception{
        return processEngine().getObject().getManagementService();
    }

}

3、resources目錄下,新建bpmn文件夾。並把流程圖文件放入,系統啓動時,bpmn文件夾下的.bpmn文件結尾的流程圖會自動部署。
最後奉上該項目的GitHub地址
項目說明:
創業者登錄界面:http://localhost:8080/EntrepreneurPage
金融機構審批:http://localhost:8080/bankPage
區級就業審批:http://localhost:8080/districtJiuYePage
重點模塊意見完成,後續部分大家可以自行練習

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章