E-Activiti7(工作流引擎)A版(理論+demo)2021年6月13日 15:30:36

非框架類總綱

http://www.reibang.com/p/d0167f082cbf

友情鏈接:

Activiti7 -A版- :http://www.reibang.com/p/bfa2d8afb50a
Activiti7 -B版- :http://www.reibang.com/p/88d03b084980
Activiti7 -C版- :http://www.reibang.com/p/485f8667f0ef

簡(jiǎn)單綱要

一屋灌、工作流介紹

1.1 概念

工作流(Workflow),就是通過計(jì)算機(jī)對(duì)業(yè)務(wù)流程自動(dòng)化執(zhí)行管理。它主要解決的是“使在多個(gè)參與者之間按照某種預(yù)定義的規(guī)則自動(dòng)進(jìn)行傳遞文檔、信息或任務(wù)的過程,從而實(shí)現(xiàn)某個(gè)預(yù)期的業(yè)務(wù)目標(biāo)樱哼,或者促使此目標(biāo)的實(shí)現(xiàn)”。

1.2 工作流系統(tǒng)

一個(gè)軟件系統(tǒng)中具有工作流的功能,我們把它稱為工作流系統(tǒng)悔捶,一個(gè)系統(tǒng)中工作流的功能是什么?就是對(duì)系統(tǒng)的業(yè)務(wù)流程進(jìn)行自動(dòng)化管理单芜,所以工作流是建立在業(yè)務(wù)流程的基礎(chǔ)上蜕该,所以一個(gè)軟件的系統(tǒng)核心根本上還是系統(tǒng)的業(yè)務(wù)流程,工作流只是協(xié)助進(jìn)行業(yè)務(wù)流程管理洲鸠。即使沒有工作流業(yè)務(wù)系統(tǒng)也可以開發(fā)運(yùn)行堂淡,只不過有了工作流可以更好的管理業(yè)務(wù)流程,提高系統(tǒng)的可擴(kuò)展性扒腕。

1.3 適用行業(yè)

消費(fèi)品行業(yè)绢淀,制造業(yè),電信服務(wù)業(yè)瘾腰,銀證險(xiǎn)等金融服務(wù)業(yè)皆的,物流服務(wù)業(yè),物業(yè)服務(wù)業(yè)蹋盆,物業(yè)管理费薄,大中型進(jìn)出口貿(mào)易公司硝全,政府事業(yè)機(jī)構(gòu),研究院所及教育服務(wù)業(yè)等楞抡,特別是大的跨國(guó)企業(yè)和集團(tuán)公司伟众。

1.4 具體應(yīng)用

1、關(guān)鍵業(yè)務(wù)流程:訂單拌倍、報(bào)價(jià)處理赂鲤、合同審核、客戶電話處理柱恤、供應(yīng)鏈管理等
2数初、行政管理類:出差申請(qǐng)、加班申請(qǐng)梗顺、請(qǐng)假申請(qǐng)泡孩、用車申請(qǐng)、各種辦公用品申請(qǐng)寺谤、購(gòu)買申請(qǐng)仑鸥、日?qǐng)?bào)周報(bào)等凡是原來手工流轉(zhuǎn)處理的行政表單。
3变屁、人事管理類:?jiǎn)T工培訓(xùn)安排眼俊、績(jī)效考評(píng)、職位變動(dòng)處理粟关、員工檔案信息管理等疮胖。
4、財(cái)務(wù)相關(guān)類:付款請(qǐng)求闷板、應(yīng)收款處理澎灸、日常報(bào)銷處理、出差報(bào)銷遮晚、預(yù)算和計(jì)劃申請(qǐng)等性昭。
5、客戶服務(wù)類:客戶信息管理县遣、客戶投訴糜颠、請(qǐng)求處理、售后服務(wù)管理等萧求。
6括蝠、特殊服務(wù)類:ISO系列對(duì)應(yīng)流程、質(zhì)量管理對(duì)應(yīng)流程饭聚、產(chǎn)品數(shù)據(jù)信息管理忌警、貿(mào)易公司報(bào)關(guān)處理、物流公司貨物跟蹤處理等各種通過表單逐步手工流轉(zhuǎn)完成的任務(wù)均可應(yīng)用工作流軟件自動(dòng)規(guī)范地實(shí)施。

1.5 實(shí)現(xiàn)方式

1法绵、在沒有專門的工作流引擎之前箕速,我們之前為了實(shí)現(xiàn)流程控制,通常的做法就是采用狀態(tài)字段的值來跟蹤流程的變化情況徙赢。這樣不用角色的用戶常柄,通過狀態(tài)字段的取值來決定記錄是否顯示哨颂。
2食茎、針對(duì)有權(quán)限可以查看的記錄,當(dāng)前用戶根據(jù)自己的角色來決定審批是否合格的操作捻悯。如果合格將狀態(tài)字段設(shè)置一個(gè)值囱淋,來代表合格;當(dāng)然如果不合格也需要設(shè)置一個(gè)值來代表不合格的情況慌盯。
3周霉、這是一種最為原始的方式。通過狀態(tài)字段雖然做到了流程控制亚皂,但是當(dāng)我們的流程發(fā)生變更的時(shí)候俱箱,這種方式所編寫的代碼也要進(jìn)行調(diào)整。
4灭必、那么有沒有專業(yè)的方式來實(shí)現(xiàn)工作流的管理呢狞谱?并且可以做到業(yè)務(wù)流程變化之后,我們的程序可以不用改變禁漓,如果可以實(shí)現(xiàn)這樣的效果跟衅,那么我們的業(yè)務(wù)系統(tǒng)的適應(yīng)能力就得到了極大提升。

二播歼、Activiti7概述

2.1 介紹

Activiti是一個(gè)工作流引擎伶跷, activiti可以將業(yè)務(wù)系統(tǒng)中復(fù)雜的業(yè)務(wù)流程抽取出來,使用專門的建模語言BPMN2.0進(jìn)行定義,業(yè)務(wù)流程按照預(yù)先定義的流程進(jìn)行執(zhí)行撩穿,實(shí)現(xiàn)了系統(tǒng)的流程由activiti進(jìn)行管理磷支,減少業(yè)務(wù)系統(tǒng)由于流程變更進(jìn)行系統(tǒng)升級(jí)改造的工作量,從而提高系統(tǒng)的健壯性食寡,同時(shí)也減少了系統(tǒng)開發(fā)維護(hù)成本雾狈。
官方網(wǎng)站:https://www.activiti.org/

2.1.1 BPM

BPM(Business Process Management),即業(yè)務(wù)流程管理抵皱,是一種規(guī)范化的構(gòu)造端到端的業(yè)務(wù)流程善榛,以持續(xù)的提高組織業(yè)務(wù)效率。常見商業(yè)管理教育如EMBA呻畸、MBA等均將BPM包含在內(nèi)移盆。

2.1.2 BPM軟件

(1)BPM軟件就是根據(jù)企業(yè)中業(yè)務(wù)環(huán)境的變化,推進(jìn)人與人之間伤为、人與系統(tǒng)之間以及系統(tǒng)與系統(tǒng)之間的整合及調(diào)整的經(jīng)營(yíng)方法與解決方案的IT工具咒循。
(2)通過BPM軟件對(duì)企業(yè)內(nèi)部及外部的業(yè)務(wù)流程的整個(gè)生命周期進(jìn)行建模、自動(dòng)化绞愚、管理監(jiān)控和優(yōu)化叙甸,使企業(yè)成本降低,利潤(rùn)得以大幅提升位衩。
(3)BPM軟件在企業(yè)中應(yīng)用領(lǐng)域廣泛裆蒸,凡是有業(yè)務(wù)流程的地方都可以BPM軟件進(jìn)行管理,比如企業(yè)人事辦公管理糖驴、采購(gòu)流程管理僚祷、公文審批流程管理、財(cái)務(wù)管理等贮缕。

2.1.3 BPMN

(1)BPMN(Business Process Model AndNotation)- 業(yè)務(wù)流程模型和符號(hào) 是由BPMI(BusinessProcess Management Initiative)開發(fā)的一套標(biāo)準(zhǔn)的業(yè)務(wù)流程建模符號(hào)辙谜,使用BPMN提供的符號(hào)可以創(chuàng)建業(yè)務(wù)流程。
(2)2004年5月發(fā)布了BPMN1.0規(guī)范.BPMI于2005年9月并入OMG(The Object Management Group對(duì)象管理組織)組織感昼。OMG于2011年1月發(fā)布BPMN2.0的最終版本装哆。
(3)BPMN 是目前被各 BPM 廠商廣泛接受的 BPM 標(biāo)準(zhǔn)。Activiti 就是使用 BPMN 2.0 進(jìn)行流程建模抑诸、流程執(zhí)行管理烂琴,它包括很多的建模符號(hào)爹殊,比如:

用一個(gè)圓圈表示蜕乡,它是流程中運(yùn)行過程中發(fā)生的事情。


image.png

活動(dòng)用圓角矩形表示梗夸,一個(gè)流程由一個(gè)活動(dòng)或多個(gè)活動(dòng)組成


image.png

Bpmn圖形其實(shí)是通過xml表示業(yè)務(wù)流程层玲,上邊的.bpmn文件使用文本編輯器打開:
<?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="myProcess" name="My process" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="創(chuàng)建請(qǐng)假單"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <userTask id="usertask2" name="部門經(jīng)理審核"></userTask>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <userTask id="usertask3" name="人事復(fù)核"></userTask>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
    <bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="130.0" y="160.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="210.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds height="55.0" width="105.0" x="360.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds height="55.0" width="105.0" x="510.0" y="150.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="660.0" y="160.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="165.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="210.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="315.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="360.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="465.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="510.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="615.0" y="177.0"></omgdi:waypoint>
        <omgdi:waypoint x="660.0" y="177.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

2.2 使用步驟

2.2.1部署activiti

Activiti是一個(gè)工作流引擎(其實(shí)就是一堆jar包API),業(yè)務(wù)系統(tǒng)訪問(操作)activiti的接口,就可以方便的操作流程相關(guān)數(shù)據(jù)辛块,這樣就可以把工作流環(huán)境與業(yè)務(wù)系統(tǒng)的環(huán)境集成在一起畔派。

2.2.2流程定義

(1)使用activiti流程建模工具(activity-designer)定義業(yè)務(wù)流程(.bpmn文件) 。
(2).bpmn文件就是業(yè)務(wù)流程定義文件润绵,通過xml定義業(yè)務(wù)流程线椰。

2.2.3流程定義部署

(1)activiti部署業(yè)務(wù)流程定義(.bpmn文件)
(2)使用activiti提供的api把流程定義內(nèi)容存儲(chǔ)起來,在Activiti執(zhí)行過程中可以查詢定義的內(nèi)容
(3)Activiti執(zhí)行把流程定義內(nèi)容存儲(chǔ)在數(shù)據(jù)庫中

2.2.4啟動(dòng)一個(gè)流程實(shí)例

(1)流程實(shí)例也叫:ProcessInstance
(2)啟動(dòng)一個(gè)流程實(shí)例表示開始一次業(yè)務(wù)流程的運(yùn)行尘盼。
(3)在員工請(qǐng)假流程定義部署完成后憨愉,如果張三要請(qǐng)假就可以啟動(dòng)一個(gè)流程實(shí)例,如果李四要請(qǐng)假也啟動(dòng)一個(gè)流程實(shí)例卿捎,兩個(gè)流程的執(zhí)行互相不影響配紫。

2.2.5用戶查詢待辦任務(wù)(Task)

因?yàn)楝F(xiàn)在系統(tǒng)的業(yè)務(wù)流程已經(jīng)交給activiti管理,通過activiti就可以查詢當(dāng)前流程執(zhí)行到哪了午阵,當(dāng)前用戶需要辦理什么任務(wù)了躺孝,這些activiti幫我們管理了,而不需要開發(fā)人員自己編寫在sql語句查詢底桂。

2.2.6用戶辦理任務(wù)

用戶查詢待辦任務(wù)后植袍,就可以辦理某個(gè)任務(wù),如果這個(gè)任務(wù)辦理完成還需要其它用戶辦理戚啥,比如采購(gòu)單創(chuàng)建后由部門經(jīng)理審核奋单,這個(gè)過程也是由activiti幫我們完成了。

2.2.7流程結(jié)束

當(dāng)任務(wù)辦理完成沒有下一個(gè)任務(wù)結(jié)點(diǎn)了猫十,這個(gè)流程實(shí)例就完成了览濒。

三、Activiti7 環(huán)境

3.1 開發(fā)環(huán)境

Jdk1.8或以上版本
Mysql 5及以上的版本
Tomcat8.5

3.2 Activiti環(huán)境

林被使用:Activiti7.0.0.Beta1 默認(rèn)支持spring5

3.2.1 下載activiti7

Activiti下載地址:http://activiti.org/download.html 拖云,Maven的依賴如下:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-dependencies</artifactId>
            <version>7.0.0.Beta1</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

activiti運(yùn)行需要有數(shù)據(jù)庫的支持贷笛,支持的數(shù)據(jù)庫有:h2, mysql, oracle, postgres, mssql, db2。

3.2.2 流程設(shè)計(jì)器IDEA下安裝

在IDEA的File菜單中找到子菜單”Settings”,后面我們?cè)龠x擇左側(cè)的“plugins”菜單宙项,如下圖所示:


image.png

3.3 Activiti的數(shù)據(jù)庫支持

Activiti 在運(yùn)行時(shí)需要數(shù)據(jù)庫的支持乏苦,使用25張表,把流程定義節(jié)點(diǎn)內(nèi)容讀取到數(shù)據(jù)庫表中尤筐,以供后續(xù)使用汇荐。

3.3.1 Activiti 支持的數(shù)據(jù)庫
數(shù)據(jù)庫類型 版本 JDBC連接示例 說明
h2 1.3.168 jdbc:h2:tcp://localhost/activiti 默認(rèn)配置的數(shù)據(jù)庫
mysql 5.1.21 jdbc:mysql://localhost:3306/activiti?autoReconnect=true 使用 mysql-connector-java 驅(qū)動(dòng)測(cè)試
oracle 11.2.0.1.0 jdbc:oracle:thin:@localhost:1521:xe
postgres 8.1 jdbc:postgresql://localhost:5432/activiti
db2 DB2 10.1 using db2jcc4 jdbc:db2://localhost:50000/activiti
mssql 2008 using sqljdbc4 jdbc:sqlserver://localhost:1433/activiti
3.3.2 在MySQL生成表
3.3.2.1 創(chuàng)建數(shù)據(jù)庫

創(chuàng)建 mysql 數(shù)據(jù)庫 activiti (名字任意):
CREATE DATABASE activiti DEFAULT CHARACTER SET utf8;

3.3.2.2 使用java代碼生成表

步驟一:創(chuàng)建 java 工程:
使用idea 創(chuàng)建 java 的maven工程,取名:activiti01

步驟二:加入 maven 依賴的坐標(biāo)(jar 包):依賴如下

  1. activiti-engine-7.0.0.beta1.jar
  2. activiti 依賴的 jar 包: mybatis盆繁、 alf4j掀淘、 log4j 等
  3. activiti 依賴的 spring 包
  4. mysql數(shù)據(jù)庫驅(qū)動(dòng)
  5. 第三方數(shù)據(jù)連接池 dbcp
  6. 單元測(cè)試 Junit-4.12.jar
<properties>
    <slf4j.version>1.6.6</slf4j.version>
    <log4j.version>1.2.12</log4j.version>
    <activiti.version>7.0.0.Beta1</activiti.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-engine</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <!-- bpmn 模型處理 -->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-bpmn-model</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <!-- bpmn 轉(zhuǎn)換 -->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-bpmn-converter</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <!-- bpmn json數(shù)據(jù)轉(zhuǎn)換 -->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-json-converter</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <!-- bpmn 布局 -->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-bpmn-layout</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <!-- activiti 云支持 -->
    <dependency>
        <groupId>org.activiti.cloud</groupId>
        <artifactId>activiti-cloud-services-api</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <!-- mysql驅(qū)動(dòng) -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.40</version>
    </dependency>
    <!-- mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>
    <!-- 鏈接池 -->
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!-- log start -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
</dependencies>

步驟三:添加log4j日志配置

我們使用log4j日志包,可以對(duì)日志進(jìn)行配置油昂,在resources 下創(chuàng)建log4j.properties

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=f:\act\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n

步驟四:添加activiti配置文件
我們使用activiti提供的默認(rèn)方式來創(chuàng)建mysql的表革娄。
默認(rèn)方式的要求是在 resources 下創(chuàng)建 activiti.cfg.xml 文件似枕,
注意:默認(rèn)方式目錄和文件名不能修改涡上,因?yàn)閍ctiviti的源碼中已經(jīng)設(shè)置癌幕,到固定的目錄讀取固定文件名的文件员寇。

步驟五:在 activiti.cfg.xml 中進(jìn)行配置
默認(rèn)方式要在在activiti.cfg.xml中bean的名字叫processEngineConfiguration,名字不可修改
在這里有兩種配置方式:一種是單獨(dú)配置數(shù)據(jù)源厕妖,一種是不單獨(dú)配置數(shù)據(jù)源

方式一:1首尼、直接配置processEngineConfiguration
processEngineConfiguration 用來創(chuàng)建 ProcessEngine,在創(chuàng)建 ProcessEngine 時(shí)會(huì)執(zhí)行數(shù)據(jù)庫的操作言秸。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!-- 默認(rèn)id對(duì)應(yīng)的值 為processEngineConfiguration -->
    <!-- processEngine Activiti的流程引擎 -->
    <bean id="processEngineConfiguration"
          class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///activiti"/>
        <property name="jdbcUsername" value="root"/>
        <property name="jdbcPassword" value="a1b2c3"/>
        <!-- activiti數(shù)據(jù)庫表處理策略 -->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>
</beans>

方式二:2饰恕、配置數(shù)據(jù)源后,在processEngineConfiguration 引用
首先配置數(shù)據(jù)源

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 這里可以使用 鏈接池 dbcp-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql:///activiti" />
        <property name="username" value="root" />
        <property name="password" value="a1b2c3" />
        <property name="maxActive" value="3" />
        <property name="maxIdle" value="1" />
    </bean>

    <bean id="processEngineConfiguration"
          class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!-- 引用數(shù)據(jù)源 上面已經(jīng)設(shè)置好了-->
        <property name="dataSource" ref="dataSource" />
        <!-- activiti數(shù)據(jù)庫表處理策略 -->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>
</beans>

步驟六: java類編寫程序生成表
創(chuàng)建一個(gè)測(cè)試類井仰,調(diào)用activiti的工具類埋嵌,生成acitivti需要的數(shù)據(jù)庫表。
直接使用activiti提供的工具類ProcessEngines俱恶,會(huì)默認(rèn)讀取classpath下的activiti.cfg.xml文件雹嗦,讀取其中的數(shù)據(jù)庫配置,創(chuàng)建 ProcessEngine合是,在創(chuàng)建ProcessEngine 時(shí)會(huì)自動(dòng)創(chuàng)建表了罪。

package com.kk.activiti.test;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.junit.Test;

public class TestDemo {
    /**
     * 生成 activiti的數(shù)據(jù)庫表
     */
    @Test
    public void testCreateDbTable() {
        //使用classpath下的activiti.cfg.xml中的配置創(chuàng)建processEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        System.out.println(processEngine);
    }
}

說明:
1、運(yùn)行以上程序段即可完成 activiti 表創(chuàng)建聪全,通過改變 activiti.cfg.xml 中databaseSchemaUpdate 參數(shù)的值執(zhí)行不同的數(shù)據(jù)表處理策略泊藕。
2、 上 邊 的 方法 getDefaultProcessEngine方法在執(zhí)行時(shí)难礼,從activiti.cfg.xml 中找固定的名稱 processEngineConfiguration 娃圆。

運(yùn)行后有25張:


image.png

3.4 表結(jié)構(gòu)介紹

3.4.1 表的命名規(guī)則和作用

看到剛才創(chuàng)建的表,我們發(fā)現(xiàn)Activiti 的表都以 ACT_ 開頭蛾茉。

第二部分是表示表的用途的兩個(gè)字母標(biāo)識(shí)讼呢。 用途也和服務(wù)的 API 對(duì)應(yīng)。
ACT_RE :'RE'表示 repository谦炬。 這個(gè)前綴的表包含了流程定義和流程靜態(tài)資源 (圖片悦屏,規(guī)則,等等)键思。
ACT_RU:'RU'表示 runtime础爬。 這些運(yùn)行時(shí)的表,包含流程實(shí)例吼鳞,任務(wù)看蚜,變量,異步任務(wù)赖条,等運(yùn)行中的數(shù)據(jù)失乾。 Activiti 只在流程實(shí)例執(zhí)行過程中保存這些數(shù)據(jù), 在流程結(jié)束時(shí)就會(huì)刪除這些記錄纬乍。 這樣運(yùn)行時(shí)表可以一直很小速度很快碱茁。
ACT_HI:'HI'表示 history。 這些表包含歷史數(shù)據(jù)仿贬,比如歷史流程實(shí)例纽竣, 變量,任務(wù)等等茧泪。
ACT_GE : GE 表示 general蜓氨。 通用數(shù)據(jù), 用于不同場(chǎng)景下

3.4.2 Activiti數(shù)據(jù)表介紹
表分類 表名 解釋
一般數(shù)據(jù)
[ACT_GE_BYTEARRAY] 通用的流程定義和流程資源
[ACT_GE_PROPERTY] 系統(tǒng)相關(guān)屬性
流程歷史記錄
[ACT_HI_ACTINST] 歷史的流程實(shí)例
[ACT_HI_ATTACHMENT] 歷史的流程附件
[ACT_HI_COMMENT] 歷史的說明性信息
[ACT_HI_DETAIL] 歷史的流程運(yùn)行中的細(xì)節(jié)信息
[ACT_HI_IDENTITYLINK] 歷史的流程運(yùn)行過程中用戶關(guān)系
[ACT_HI_PROCINST] 歷史的流程實(shí)例
[ACT_HI_TASKINST] 歷史的任務(wù)實(shí)例
[ACT_HI_VARINST] 歷史的流程運(yùn)行中的變量信息
流程定義表
[ACT_RE_DEPLOYMENT] 部署單元信息
[ACT_RE_MODEL] 模型信息
[ACT_RE_PROCDEF] 已部署的流程定義
運(yùn)行實(shí)例表
[ACT_RU_EVENT_SUBSCR] 運(yùn)行時(shí)事件
[ACT_RU_EXECUTION] 運(yùn)行時(shí)流程執(zhí)行實(shí)例
[ACT_RU_IDENTITYLINK] 運(yùn)行時(shí)用戶關(guān)系信息队伟,存儲(chǔ)任務(wù)節(jié)點(diǎn)與參與者的相關(guān)信息
[ACT_RU_JOB] 運(yùn)行時(shí)作業(yè)
[ACT_RU_TASK] 運(yùn)行時(shí)任務(wù)
[ACT_RU_VARIABLE] 運(yùn)行時(shí)變量表

四穴吹、Activiti 類關(guān)系圖

上面我們完成了Activiti數(shù)據(jù)庫表的生成,java代碼中我們調(diào)用Activiti的工具類嗜侮,下面來了解Activiti的類關(guān)系

4.1 類關(guān)系圖

image.png

在新版本中港令,我們通過實(shí)驗(yàn)可以發(fā)現(xiàn)IdentityService,F(xiàn)ormService兩個(gè)Serivce都已經(jīng)刪除了锈颗。
所以后面我們對(duì)于這兩個(gè)Service也不講解了顷霹,但老版本中還是有這兩個(gè)Service,林被要你們需要了解一下

4.2 activiti.cfg.xml

activiti的引擎配置文件击吱,包括:ProcessEngineConfiguration的定義淋淀、數(shù)據(jù)源定義、事務(wù)管理器等覆醇,此文件其實(shí)就是一個(gè)spring配置文件朵纷。

4.3 流程引擎配置類

流程引擎的配置類(ProcessEngineConfiguration),通過ProcessEngineConfiguration可以創(chuàng)建工作流引擎ProceccEngine永脓,常用的兩種方法如下:

4.3.1 StandaloneProcessEngineConfiguration

使用StandaloneProcessEngineConfigurationActiviti可以單獨(dú)運(yùn)行柴罐,來創(chuàng)建ProcessEngine,Activiti會(huì)自己處理事務(wù)憨奸。
配置文件方式:通常在activiti.cfg.xml配置文件中定義一個(gè)id為 processEngineConfiguration 的bean.

<bean id="processEngineConfiguration"
          class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!--配置數(shù)據(jù)庫相關(guān)的信息-->
        <!--數(shù)據(jù)庫驅(qū)動(dòng)-->
        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
        <!--數(shù)據(jù)庫鏈接-->
        <property name="jdbcUrl" value="jdbc:mysql:///activiti"/>
        <!--數(shù)據(jù)庫用戶名-->
        <property name="jdbcUsername" value="root"/>
        <!--數(shù)據(jù)庫密碼-->
        <property name="jdbcPassword" value="a1b2c3"/>
        <!--actviti數(shù)據(jù)庫表在生成時(shí)的策略  true - 如果數(shù)據(jù)庫中已經(jīng)存在相應(yīng)的表革屠,那么直接使用,如果不存在排宰,那么會(huì)創(chuàng)建-->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>

加入連接池:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///activiti"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="maxActive" value="3"/>
        <property name="maxIdle" value="1"/>
    </bean>
    <!--在默認(rèn)方式下 bean的id  固定為 processEngineConfiguration-->
    <bean id="processEngineConfiguration"
          class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!--引入上面配置好的 鏈接池-->
        <property name="dataSource" ref="dataSource"/>
        <!--actviti數(shù)據(jù)庫表在生成時(shí)的策略  true - 如果數(shù)據(jù)庫中已經(jīng)存在相應(yīng)的表似芝,那么直接使用,如果不存在板甘,那么會(huì)創(chuàng)建-->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>
</beans>

4.3.2 SpringProcessEngineConfiguration

通過org.activiti.spring.SpringProcessEngineConfiguration 與Spring整合党瓮。
創(chuàng)建spring與activiti的整合配置文件:activity-spring.cfg.xml(名稱可修改)

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
 xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
       http://www.springframework.org/schema/mvc 
       http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd 
       http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.1.xsd 
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-3.1.xsd 
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-3.1.xsd ">
    <!-- 工作流引擎配置bean -->
    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
       <!-- 數(shù)據(jù)源 -->
       <property name="dataSource" ref="dataSource" />
       <!-- 使用spring事務(wù)管理器 -->
       <property name="transactionManager" ref="transactionManager" />
       <!-- 數(shù)據(jù)庫策略 -->
       <property name="databaseSchemaUpdate" value="drop-create" />
       <!-- activiti的定時(shí)任務(wù)關(guān)閉 -->
      <property name="jobExecutorActivate" value="false" />
    </bean>
    <!-- 流程引擎 -->
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
       <property name="processEngineConfiguration" ref="processEngineConfiguration" />
    </bean>
    <!-- 資源服務(wù)service -->
    <bean id="repositoryService" factory-bean="processEngine"
       factory-method="getRepositoryService" />
    <!-- 流程運(yùn)行service -->
    <bean id="runtimeService" factory-bean="processEngine"
       factory-method="getRuntimeService" />
    <!-- 任務(wù)管理service -->
    <bean id="taskService" factory-bean="processEngine"
       factory-method="getTaskService" />
    <!-- 歷史管理service -->
    <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />
    <!-- 用戶管理service -->
    <bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService" />
    <!-- 引擎管理service -->
    <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />
    <!-- 數(shù)據(jù)源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
       <property name="driverClassName" value="com.mysql.jdbc.Driver" />
       <property name="url" value="jdbc:mysql://localhost:3306/activiti" />
       <property name="username" value="root" />
       <property name="password" value="a1b2c3" />
       <property name="maxActive" value="3" />
       <property name="maxIdle" value="1" />
    </bean>
    <!-- 事務(wù)管理器 -->
    <bean id="transactionManager"
     class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
       <tx:attributes></tx:attributes>
           <!-- 傳播行為 -->
           <tx:method name="save*" propagation="REQUIRED" />
           <tx:method name="insert*" propagation="REQUIRED" />
           <tx:method name="delete*" propagation="REQUIRED" />
           <tx:method name="update*" propagation="REQUIRED" />
           <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
           <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
        </tx:attributes>
    </tx:advice>
    <!-- 切面,根據(jù)具體項(xiàng)目修改切點(diǎn)配置 -->
    <aop:config proxy-target-class="true">
       <aop:advisor advice-ref="txAdvice"  pointcut="execution(* com.kk.ihrm.service.impl.*.(..))"* />
   </aop:config>
</beans>

創(chuàng)建processEngineConfiguration

ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml")

上邊的代碼要求activiti.cfg.xml中必須有一個(gè)processEngineConfiguration的bean也可以使用下邊的方法盐类,
更改bean 的名字:

ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(String resource, String beanName);

4.4 工作流引擎創(chuàng)建

工作流引擎(ProcessEngine)寞奸,相當(dāng)于一個(gè)門面接口呛谜,通過ProcessEngineConfiguration創(chuàng)建processEngine,通過ProcessEngine創(chuàng)建各個(gè)service接口枪萄。

4.4.1 默認(rèn)創(chuàng)建方式

將activiti.cfg.xml文件名及路徑固定隐岛,且activiti.cfg.xml文件中有 processEngineConfiguration的配置, 可以使用如下代碼創(chuàng)建processEngine:

//直接使用工具類 ProcessEngines瓷翻,使用classpath下的activiti.cfg.xml中的配置創(chuàng)建processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println(processEngine);

4.4.2 一般創(chuàng)建方式

//先構(gòu)建ProcessEngineConfiguration
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
//通過ProcessEngineConfiguration創(chuàng)建ProcessEngine聚凹,此時(shí)會(huì)創(chuàng)建數(shù)據(jù)庫
ProcessEngine processEngine = configuration.buildProcessEngine();

4.5 Servcie服務(wù)接口

Service是工作流引擎提供用于進(jìn)行工作流部署、執(zhí)行齐帚、管理的服務(wù)接口妒牙,我們使用這些接口可以就是操作服務(wù)對(duì)應(yīng)的數(shù)據(jù)表

4.5.1 Service創(chuàng)建方式

通過ProcessEngine創(chuàng)建Service,方式如下:

RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();

4.5.2 Service總覽

service名稱 service作用
RepositoryService activiti的資源管理類
RuntimeService activiti的流程運(yùn)行管理類
TaskService activiti的任務(wù)管理類
HistoryService activiti的歷史管理類
ManagerService activiti的引擎管理類

RepositoryService
(1)是activiti的資源管理類对妄,提供了管理和控制流程發(fā)布包和流程定義的操作湘今。使用工作流建模工具設(shè)計(jì)的業(yè)務(wù)流程圖需要使用此service將流程定義文件的內(nèi)容部署到計(jì)算機(jī)。
除了部署流程定義以外還可以:查詢引擎中的發(fā)布包和流程定義剪菱。
(2)暫拖蠡耄或激活發(fā)布包,對(duì)應(yīng)全部和特定流程定義琅豆。 暫停意味著它們不能再執(zhí)行任何操作了愉豺,激活是對(duì)應(yīng)的反向操作。獲得多種資源茫因,像是包含在發(fā)布包里的文件蚪拦, 或引擎自動(dòng)生成的流程圖。
(3)獲得流程定義的pojo版本冻押, 可以用來通過java解析流程驰贷,而不必通過xml。

RuntimeService
Activiti的流程運(yùn)行管理類洛巢±ㄌ唬可以從這個(gè)服務(wù)類中獲取很多關(guān)于流程執(zhí)行相關(guān)的信息

TaskService
Activiti的任務(wù)管理類「遘裕可以從這個(gè)類中獲取任務(wù)的信息锹锰。

HistoryService
Activiti的歷史管理類,可以查詢歷史信息漓库,執(zhí)行流程時(shí)恃慧,引擎會(huì)保存很多數(shù)據(jù)(根據(jù)配置),比如流程實(shí)例啟動(dòng)時(shí)間渺蒿,任務(wù)的參與者痢士, 完成任務(wù)的時(shí)間,每個(gè)流程實(shí)例的執(zhí)行路徑茂装,等等怠蹂。 這個(gè)服務(wù)主要通過查詢功能來獲得這些數(shù)據(jù)善延。

ManagementService
Activiti的引擎管理類,提供了對(duì) Activiti 流程引擎的管理和維護(hù)功能城侧,這些功能不在工作流驅(qū)動(dòng)的應(yīng)用程序中使用易遣,主要用于 Activiti 系統(tǒng)的日常維護(hù)。

五赞庶、Activiti 入門 (demo)

創(chuàng)建Activiti工作流主要包含以下幾步:
1、定義流程澳骤,按照BPMN的規(guī)范歧强,使用流程定義工具,用流程符號(hào)把整個(gè)流程描述出來
2为肮、部署流程摊册,把畫好的流程定義文件,加載到數(shù)據(jù)庫中颊艳,生成表的數(shù)據(jù)
3茅特、啟動(dòng)流程,使用java代碼來操作數(shù)據(jù)庫表中的內(nèi)容

5.1 流程符號(hào)

BPMN 2.0是業(yè)務(wù)流程建模符號(hào)2.0的縮寫棋枕。
它由Business Process Management Initiative這個(gè)非營(yíng)利協(xié)會(huì)創(chuàng)建并不斷發(fā)展白修。作為一種標(biāo)識(shí),BPMN 2.0是使用一些符號(hào)來明確業(yè)務(wù)流程設(shè)計(jì)流程圖的一整套符號(hào)規(guī)范重斑,它能增進(jìn)業(yè)務(wù)建模時(shí)的溝通效率兵睛。
目前BPMN2.0是最新的版本,它用于在BPM上下文中進(jìn)行布局和可視化的溝通窥浪。
以下為常用的流程符號(hào):

5.1.1事件 Event:

image.png

5.1.2活動(dòng) Activity

活動(dòng)是工作或任務(wù)的一個(gè)通用術(shù)語祖很。一個(gè)活動(dòng)可以是一個(gè)任務(wù),還可以是一個(gè)當(dāng)前流程的子處理流程漾脂; 其次假颇,你還可以為活動(dòng)指定不同的類型。常見活動(dòng)如下:


image.png

5.1.3 網(wǎng)關(guān) GateWay

網(wǎng)關(guān)用來處理決策骨稿,有幾種常用網(wǎng)關(guān)需要了解:


image.png

5.1.3.1 排他網(wǎng)關(guān) (x)

(1)只有一條路徑會(huì)被選擇笨鸡。流程執(zhí)行到該網(wǎng)關(guān)時(shí),按照輸出流的順序逐個(gè)計(jì)算坦冠,當(dāng)條件的計(jì)算結(jié)果為true時(shí)镜豹,繼續(xù)執(zhí)行當(dāng)前網(wǎng)關(guān)的輸出流;

(2)如果多條線路計(jì)算結(jié)果都是 true蓝牲,則會(huì)執(zhí)行第一個(gè)值為 true 的線路趟脂。如果所有網(wǎng)關(guān)計(jì)算結(jié)果沒有true,則引擎會(huì)拋出異常例衍。

(3)排他網(wǎng)關(guān)需要和條件順序流結(jié)合使用昔期,default 屬性指定默認(rèn)順序流已卸,當(dāng)所有的條件不滿足時(shí)會(huì)執(zhí)行默認(rèn)順序流。

5.1.3.2 并行網(wǎng)關(guān) (+)

(1)所有路徑會(huì)被同時(shí)選擇

(2)拆分 —— 并行執(zhí)行所有輸出順序流硼一,為每一條順序流創(chuàng)建一個(gè)并行執(zhí)行線路累澡。

(3)合并 —— 所有從并行網(wǎng)關(guān)拆分并執(zhí)行完成的線路均在此等候,直到所有的線路都執(zhí)行完成才繼續(xù)向下執(zhí)行般贼。

5.1.3.3 包容網(wǎng)關(guān) (+)

(1)可以同時(shí)執(zhí)行多條線路愧哟,也可以在網(wǎng)關(guān)上設(shè)置條件

(2)拆分 —— 計(jì)算每條線路上的表達(dá)式,當(dāng)表達(dá)式計(jì)算結(jié)果為true時(shí)哼蛆,創(chuàng)建一個(gè)并行線路并繼續(xù)執(zhí)行

(3)合并 —— 所有從并行網(wǎng)關(guān)拆分并執(zhí)行完成的線路均在此等候蕊梧,直到所有的線路都執(zhí)行完成才繼續(xù)向下執(zhí)行。

5.1.3.4 事件網(wǎng)關(guān) (+)

專門為中間捕獲事件設(shè)置的腮介,允許設(shè)置多個(gè)輸出流指向多個(gè)不同的中間捕獲事件肥矢。當(dāng)流程執(zhí)行到事件網(wǎng)關(guān)后,流程處于等待狀態(tài)叠洗,需要等待拋出事件才能將等待狀態(tài)轉(zhuǎn)換為活動(dòng)狀態(tài)甘改。

5.1.5 流向 Flow

流是連接兩個(gè)流程節(jié)點(diǎn)的連線。常見的流向包含以下幾種:


image.png

5.2 流程設(shè)計(jì)器使用

5.2.1 Activiti-Designer使用

5.2.1.1 Palette(畫板)

在idea中安裝插件即可使用灭抑,畫板中包括以下結(jié)點(diǎn):

Connection—連接
Event---事件
Task---任務(wù)
Gateway---網(wǎng)關(guān)
Container—容器
Boundary event—邊界事件
Intermediate event- -中間事件
流程圖設(shè)計(jì)完畢保存生成.bpmn文件

5.2.1.2 新建流程(IDEA工具)

首先選中存放圖形的目錄(選擇resources下的bpmn目錄)十艾,點(diǎn)擊菜單:New -> BpmnFile,如圖:


image.png

彈出如下圖所示框腾节,輸入evection 表示 出差審批流程:


image.png

起完名字evection后(默認(rèn)擴(kuò)展名為bpmn)疟羹,就可以看到流程設(shè)計(jì)頁面,如圖所示:
image.png

5.2.1.3 繪制流程

使用滑板來繪制流程禀倔,通過從右側(cè)把圖標(biāo)拖拽到左側(cè)的畫板榄融,最終效果如下:


image.png

5.2.1.4 指定流程定義Key

image.png

5.2.1.5 指定任務(wù)負(fù)責(zé)人

在properties視圖指定每個(gè)任務(wù)結(jié)點(diǎn)的負(fù)責(zé)人,如:填寫出差申請(qǐng)的負(fù)責(zé)人為 mykk


image.png

六救湖、流程操作

流程定義:

1 概述

(1)流程定義是線下按照bpmn2.0標(biāo)準(zhǔn)去描述 業(yè)務(wù)流程愧杯,通常使用idea中的插件對(duì)業(yè)務(wù)流程進(jìn)行建模。
(2)使用idea下的designer設(shè)計(jì)器繪制流程鞋既,并會(huì)生成兩個(gè)文件:.bpmn和.png

2 .bpmn文件

(1)使用activiti-desinger設(shè)計(jì)業(yè)務(wù)流程力九,會(huì)生成.bpmn文件,上面我們已經(jīng)創(chuàng)建好了bpmn文件
(2)BPMN 2.0根節(jié)點(diǎn)是definitions節(jié)點(diǎn)邑闺。 這個(gè)元素中跌前,可以定義多個(gè)流程定義(不過我們建議每個(gè)文件只包含一個(gè)流程定義, 可以簡(jiǎn)化開發(fā)過程中的維護(hù)難度)陡舅。 注意抵乓,definitions元素 最少也要包含xmlns 和 targetNamespace的聲明。 targetNamespace可以是任意值,它用來對(duì)流程實(shí)例進(jìn)行分類灾炭。
(3)流程定義部分:定義了流程每個(gè)結(jié)點(diǎn)的描述及結(jié)點(diǎn)之間的流程流轉(zhuǎn)茎芋。
(4)流程布局定義:定義流程每個(gè)結(jié)點(diǎn)在流程圖上的位置坐標(biāo)等信息。

3 生成.png圖片文件

3.1 修改文件后綴為xml

首先將evection.bpmn文件改名為evection.xml蜈出,如下圖:


image.png
3.2 使用designer設(shè)計(jì)器打開.xml文件

在evection.xml文件上面田弥,點(diǎn)右鍵并選擇Diagrams菜單,再選擇Show BPMN2.0 Designer…


image.png
3.3 查看打開的文件

打開后铡原,卻出現(xiàn)亂碼偷厦,如圖:


image.png
3.4 解決中文亂碼

1、打開Settings燕刻,找到File Encodings只泼,把encoding的選項(xiàng)都選擇UTF-8


image.png

2、打開IDEA安裝路徑酌儒,找到如下的安裝目錄


image.png

根據(jù)自己所安裝的版本來決定辜妓,我使用的是64位的idea枯途,所以在idea64.exe.vmoptions文件的最后一行追加一條命令: -Dfile.encoding=UTF-8
如下所示:

image.png

一定注意忌怎,不要有空格,否則重啟IDEA時(shí)會(huì)打不開酪夷,然后 重啟IDEA榴啸。
如果以上方法已經(jīng)做完,還出現(xiàn)亂碼晚岭,就再修改一個(gè)文件鸥印,并在文件的末尾添加: -Dfile.encoding=UTF-8,然后重啟idea坦报,如圖:


image.png

最后重新在evection.xml文件上面库说,點(diǎn)右鍵并選擇Diagrams菜單,再選擇Show BPMN2.0 Designer…片择,看到生成圖片潜的,如圖:


image.png
3.5 導(dǎo)出為圖片文件

點(diǎn)擊Export To File的小圖標(biāo),打開如下窗口字管,注意填寫文件名及擴(kuò)展名啰挪,選擇好保存圖片的位置:


image.png

image.png

然后,我們把png文件拷貝到resources下的bpmn目錄嘲叔,并且把evection.xml改名為evection.bpmn亡呵。

流程定義部署:

1、概述

(1)將上面在設(shè)計(jì)器中定義的流程部署到activiti數(shù)據(jù)庫中硫戈,就是流程定義部署锰什。
(2)通過調(diào)用activiti的api將流程定義的bpmn和png兩個(gè)文件一個(gè)一個(gè)添加部署到activiti中,也可以將兩個(gè)文件打成zip包進(jìn)行部署

2、單個(gè)文件部署方式

分別將bpmn文件和png圖片文件部署歇由。

package com.kk.activiti;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.junit.Test;

public class ActivitiDemo {

    /**
     * 部署流程定義
     */
    @Test
    public void testDeployment() {
//        1卵牍、創(chuàng)建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine ( );
//        2、得到RepositoryService實(shí)例
        RepositoryService repositoryService = processEngine.getRepositoryService ( );
//        3沦泌、使用RepositoryService進(jìn)行部署
        Deployment deployment = repositoryService.createDeployment ( )
                .addClasspathResource ("bpmn/evection.bpmn") // 添加bpmn資源
                .addClasspathResource ("bpmn/evection.png")  // 添加png資源
                .name ("請(qǐng)假申請(qǐng)流程")
                .deploy ( );
//        4糊昙、輸出部署信息
        System.out.println ("流程部署id:" + deployment.getId ( ));
        System.out.println ("流程部署名稱:" + deployment.getName ( ));
    }
}

執(zhí)行此操作后activiti會(huì)將上邊代碼中指定的bpm文件和圖片文件保存在activiti數(shù)據(jù)庫。

3谢谦、壓縮包部署方式

將evection.bpmn和evection.png壓縮成zip包释牺。

@Test
    public void deployProcessByZip() {
        // 定義zip輸入流
        InputStream inputStream = this
                .getClass()
                .getClassLoader()
                .getResourceAsStream(
                        "bpmn/evection.zip");
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        // 獲取repositoryService
        RepositoryService repositoryService = processEngine
                .getRepositoryService();
        // 流程部署
        Deployment deployment = repositoryService.createDeployment()
                .addZipInputStream(zipInputStream)
                .deploy();
        System.out.println("流程部署id:" + deployment.getId());
        System.out.println("流程部署名稱:" + deployment.getName());
    }

執(zhí)行此操作后activiti會(huì)將上邊代碼中指定的bpm文件和圖片文件保存在activiti數(shù)據(jù)庫。

4回挽、操作數(shù)據(jù)表

流程定義部署后操作activiti的3張表如下:

act_re_deployment 流程定義部署表没咙,每部署一次增加一條記錄
act_re_procdef 流程定義表,部署每個(gè)新的流程定義都會(huì)在這張表中增加一條記錄
act_ge_bytearray 流程資源表

接下來我們來看看千劈,寫入了什么數(shù)據(jù):
(1)SELECT * FROM act_re_deployment #流程定義部署表祭刚,記錄流程部署信息

image.png

(2)SELECT * FROM act_re_procdef #流程定義表,記錄流程定義信息
注意墙牌,KEY 這個(gè)字段是用來唯一識(shí)別不同流程的關(guān)鍵字

image.png

(3)SELECT * FROM act_ge_bytearray #資源表
image.png

注意:
act_re_deployment和act_re_procdef一對(duì)多關(guān)系涡驮,一次部署在流程部署表生成一條記錄,但一次部署可以部署多個(gè)流程定義喜滨,每個(gè)流程定義在流程定義表生成一條記錄捉捅。每一個(gè)流程定義在act_ge_bytearray會(huì)存在兩個(gè)資源記錄,bpmn和png虽风。

建議:一次部署一個(gè)流程棒口,這樣部署表和流程定義表是一對(duì)一有關(guān)系,方便讀取流程部署及流程定義信息辜膝。

5无牵、啟動(dòng)流程實(shí)例

流程定義部署在activiti后就可以通過工作流管理業(yè)務(wù)流程了,也就是說上邊部署的出差申請(qǐng)流程可以使用了厂抖。

針對(duì)該流程茎毁,啟動(dòng)一個(gè)流程表示發(fā)起一個(gè)新的出差申請(qǐng)單,這就相當(dāng)于java類與java對(duì)象的關(guān)系验游,類定義好后需要new創(chuàng)建一個(gè)對(duì)象使用充岛,當(dāng)然可以new多個(gè)對(duì)象。對(duì)于請(qǐng)出差申請(qǐng)流程耕蝉,張三發(fā)起一個(gè)出差申請(qǐng)單需要啟動(dòng)一個(gè)流程實(shí)例崔梗,出差申請(qǐng)單發(fā)起一個(gè)出差單也需要啟動(dòng)一個(gè)流程實(shí)例。

代碼如下:

/**
     * 啟動(dòng)流程實(shí)例
     */
    @Test
    public void testStartProcess() {
//        1垒在、創(chuàng)建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine ( );
//        2蒜魄、獲取RunTimeService
        RuntimeService runtimeService = processEngine.getRuntimeService ( );
//        3、根據(jù)流程定義Id啟動(dòng)流程
        ProcessInstance processInstance = runtimeService
                .startProcessInstanceByKey ("myEvection");
//        輸出內(nèi)容
        System.out.println ("流程定義id:" + processInstance.getProcessDefinitionId ( ));
        System.out.println ("流程實(shí)例id:" + processInstance.getId ( ));
        System.out.println ("當(dāng)前活動(dòng)Id:" + processInstance.getActivityId ( ));
    }

操作數(shù)據(jù)表

act_hi_actinst 流程實(shí)例執(zhí)行歷史
act_hi_identitylink 流程的參與用戶歷史信息
act_hi_procinst 流程實(shí)例歷史信息
act_hi_taskinst 流程任務(wù)歷史信息
act_ru_execution 流程執(zhí)行信息
act_ru_identitylink 流程的參與用戶信息
act_ru_task 任務(wù)信息

6、任務(wù)查詢

流程啟動(dòng)后谈为,任務(wù)的負(fù)責(zé)人就可以查詢自己當(dāng)前需要處理的任務(wù)旅挤,查詢出來的任務(wù)都是該用戶的待辦任務(wù)。

/**
     * 查詢當(dāng)前個(gè)人待執(zhí)行的任務(wù)
      */
    @Test
    public void testFindPersonalTaskList() {
//        任務(wù)負(fù)責(zé)人
        String assignee = "zhangsan";
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        創(chuàng)建TaskService
        TaskService taskService = processEngine.getTaskService();
//        根據(jù)流程key 和 任務(wù)負(fù)責(zé)人 查詢?nèi)蝿?wù)
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey("myEvection") //流程Key
                .taskAssignee(assignee)//只查詢?cè)撊蝿?wù)負(fù)責(zé)人的任務(wù)
                .list();

        for (Task task : list) {

            System.out.println("流程實(shí)例id:" + task.getProcessInstanceId());
            System.out.println("任務(wù)id:" + task.getId());
            System.out.println("任務(wù)負(fù)責(zé)人:" + task.getAssignee());
            System.out.println("任務(wù)名稱:" + task.getName());

        }
    }

7伞鲫、流程任務(wù)處理

任務(wù)負(fù)責(zé)人查詢待辦任務(wù),選擇任務(wù)進(jìn)行處理柒瓣,完成任務(wù)磺平。

    // 完成任務(wù)
    @Test
    public void completTask() {
//        獲取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine ( );
//        獲取taskService
        TaskService taskService = processEngine.getTaskService ( );

//        根據(jù)流程key 和 任務(wù)的負(fù)責(zé)人 查詢?nèi)蝿?wù)
//        返回一個(gè)任務(wù)對(duì)象
        Task task = taskService.createTaskQuery ( )
                .processDefinitionKey ("myEvection") //流程Key
                //.taskAssignee("mykk")  //要查詢的負(fù)責(zé)人
                .singleResult ( );

//        完成任務(wù),參數(shù):任務(wù)id
        taskService.complete (task.getId ( ));
        
        System.out.println ("流程實(shí)例id:" + task.getProcessInstanceId ( ));
        System.out.println ("任務(wù)id:" + task.getId ( ));
        System.out.println ("任務(wù)負(fù)責(zé)人:" + task.getAssignee ( ));
        System.out.println ("任務(wù)名稱:" + task.getName ( ));

        // 第一次運(yùn)行后返回  mykk,
        // 第二次運(yùn)行后返回  tom,
        // 第三次運(yùn)行后返回  jack,
    } 

8、流程定義信息查詢

查詢流程相關(guān)信息薛训,包含流程定義媒吗,流程部署仑氛,流程定義版本

 /**
     * 查詢流程定義
     */
    @Test
    public void queryProcessDefinition(){
        //        獲取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
//        得到ProcessDefinitionQuery 對(duì)象
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
//          查詢出當(dāng)前所有的流程定義
//          條件:processDefinitionKey =evection
//          orderByProcessDefinitionVersion 按照版本排序
//        desc倒敘
//        list 返回集合
        List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("myEvection")
                .orderByProcessDefinitionVersion()
                .desc()
                .list();
//      輸出流程定義信息
        for (ProcessDefinition processDefinition : definitionList) {
            System.out.println("流程定義 id="+processDefinition.getId());
            System.out.println("流程定義 name="+processDefinition.getName());
            System.out.println("流程定義 key="+processDefinition.getKey());
            System.out.println("流程定義 Version="+processDefinition.getVersion());
            System.out.println("流程部署ID ="+processDefinition.getDeploymentId());
        }

    }

9乙埃、流程刪除

    /**
     * 流程刪除
     */
    public void deleteDeployment() {
        // 流程部署id
        String deploymentId = "1";

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 通過流程引擎獲取repositoryService
        RepositoryService repositoryService = processEngine
                .getRepositoryService();
        //刪除流程定義,如果該流程定義已有流程實(shí)例啟動(dòng)則刪除時(shí)出錯(cuò)
        repositoryService.deleteDeployment(deploymentId);
        //設(shè)置true 級(jí)聯(lián)刪除流程定義锯岖,即使該流程有流程實(shí)例啟動(dòng)也可以刪除介袜,設(shè)置為false非級(jí)別刪除方式,如果流程
        //repositoryService.deleteDeployment(deploymentId, true);
    }

說明:

  1.   使用repositoryService刪除流程定義出吹,歷史表信息不會(huì)被刪除
    
  2.   如果該流程定義下沒有正在運(yùn)行的流程遇伞,則可以用普通刪除。
    

如果該流程定義下存在已經(jīng)運(yùn)行的流程捶牢,使用普通刪除報(bào)錯(cuò)鸠珠,可用級(jí)聯(lián)刪除方法將流程及相關(guān)記錄全部刪除。
先刪除沒有完成流程節(jié)點(diǎn)秋麸,最后就可以完全刪除流程定義信息
項(xiàng)目開發(fā)中級(jí)聯(lián)刪除操作一般只開放給超級(jí)管理員使用.

10渐排、流程資源下載

現(xiàn)在我們的流程資源文件已經(jīng)上傳到數(shù)據(jù)庫了灸蟆,如果其他用戶想要查看這些資源文件驯耻,可以從數(shù)據(jù)庫中把資源文件下載到本地。
解決方案有:
1、jdbc對(duì)blob類型可缚,clob類型數(shù)據(jù)讀取出來霎迫,保存到文件目錄
2、使用activiti的api來實(shí)現(xiàn):
使用commons-io.jar 解決IO的操作
引入commons-io依賴包

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>
import org.apache.commons.io.IOUtils;

@Test
    public void deleteDeployment(){
//        獲取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        獲取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
//        根據(jù)部署id 刪除部署信息,如果想要級(jí)聯(lián)刪除帘靡,可以添加第二個(gè)參數(shù)知给,true
        repositoryService.deleteDeployment("1");
    }

    public void  queryBpmnFile() throws IOException {
//        1、得到引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2描姚、獲取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
//        3炼鞠、得到查詢器:ProcessDefinitionQuery,設(shè)置查詢條件,得到想要的流程定義
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("myEvection")
                .singleResult();
//        4轰胁、通過流程定義信息谒主,得到部署ID
        String deploymentId = processDefinition.getDeploymentId();
//        5、通過repositoryService的方法赃阀,實(shí)現(xiàn)讀取圖片信息和bpmn信息
//        png圖片的流
        InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
//        bpmn文件的流
        InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());
//        6霎肯、構(gòu)造OutputStream流
        File file_png = new File("d:/evectionflow01.png");
        File file_bpmn = new File("d:/evectionflow01.bpmn");
        FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
        FileOutputStream pngOut = new FileOutputStream(file_png);
//        7、輸入流榛斯,輸出流的轉(zhuǎn)換
        IOUtils.copy(pngInput,pngOut);
        IOUtils.copy(bpmnInput,bpmnOut);
//        8观游、關(guān)閉流
        pngOut.close();
        bpmnOut.close();
        pngInput.close();
        bpmnInput.close();
    }

說明:

  1.   deploymentId為流程部署ID
    
  2.   resource_name為act_ge_bytearray表中NAME_列的值
    
  3.   使用repositoryService的getDeploymentResourceNames方法可以獲取指定部署下得所有文件的名稱
    
  4.   使用repositoryService的getResourceAsStream方法傳入部署ID和資源圖片名稱可以獲取部署下指定名稱文件的輸入流
    

最后的將輸入流中的圖片資源進(jìn)行輸出。

11驮俗、流程歷史信息的查看

即使流程定義已經(jīng)刪除了懂缕,流程執(zhí)行的歷史信息通過前面的分析,依然保存在activiti的act_hi_*相關(guān)的表中王凑。所以我們還是可以查詢流程執(zhí)行的歷史信息搪柑,可以通過HistoryService來查看相關(guān)的歷史記錄。

    /**
     * 查看歷史信息
     */
    @Test
    public void findHistoryInfo(){
//      獲取引擎
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        獲取HistoryService
        HistoryService historyService = processEngine.getHistoryService();
//        獲取 actinst表的查詢對(duì)象
        HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//        查詢 actinst表索烹,條件:根據(jù) InstanceId 查詢
//        instanceQuery.processInstanceId("2501");
//        查詢 actinst表工碾,條件:根據(jù) DefinitionId 查詢
        instanceQuery.processDefinitionId("myEvection:1:4");
//        增加排序操作,orderByHistoricActivityInstanceStartTime 根據(jù)開始時(shí)間排序 asc 升序
        instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
//        查詢所有內(nèi)容
        List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
//        輸出
        for (HistoricActivityInstance hi : activityInstanceList) {
            System.out.println(hi.getActivityId());
            System.out.println(hi.getActivityName());
            System.out.println(hi.getProcessDefinitionId());
            System.out.println(hi.getProcessInstanceId());
            System.out.println("<==========================>");
        }
    }

參考文檔

1、亂碼:https://blog.csdn.net/bobozai86/article/details/104243774
2百姓、

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末渊额,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子垒拢,更是在濱河造成了極大的恐慌旬迹,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件求类,死亡現(xiàn)場(chǎng)離奇詭異奔垦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)仑嗅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門宴倍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來张症,“玉大人,你說我怎么就攤上這事鸵贬∷姿” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵阔逼,是天一觀的道長(zhǎng)兆衅。 經(jīng)常有香客問我,道長(zhǎng)嗜浮,這世上最難降的妖魔是什么羡亩? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮危融,結(jié)果婚禮上魁淳,老公的妹妹穿的比我還像新娘霞怀。我一直安慰自己备韧,他們只是感情好焙矛,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蛋勺,像睡著了一般瓦灶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抱完,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天贼陶,我揣著相機(jī)與錄音,去河邊找鬼巧娱。 笑死碉怔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的家卖。 我是一名探鬼主播眨层,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼庙楚,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼上荡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起馒闷,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤酪捡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后纳账,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體逛薇,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年疏虫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了永罚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啤呼。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖呢袱,靈堂內(nèi)的尸體忽然破棺而出官扣,到底是詐尸還是另有隱情,我是刑警寧澤羞福,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布惕蹄,位于F島的核電站,受9級(jí)特大地震影響治专,放射性物質(zhì)發(fā)生泄漏卖陵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一张峰、第九天 我趴在偏房一處隱蔽的房頂上張望泪蔫。 院中可真熱鬧,春花似錦喘批、人聲如沸鸥滨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽婿滓。三九已至,卻和暖如春粥喜,著一層夾襖步出監(jiān)牢的瞬間凸主,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工额湘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卿吐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓锋华,卻偏偏與公主長(zhǎng)得像嗡官,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子毯焕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容