天天看點

Activiti工作流-入門

Activiti概述

工作流概念

工作流(Workflow),指“業務過程的部分或整體在計算機應用環境下的自動化”。是對工作流程及其各操作步驟之間業務規則的抽象、概括描述。

通俗的說,流程(過程)就是多個人在一起合作完成某件事情的步驟,把步驟程式設計計算機能了解的形式,就是工作流。

工作流是研究一個群體如何在計算機的幫助下實作協同工作的,其主要解決的問題是:為了實作某個業務目标,利用計算機在多個參與者(Actor)之間按某種預定規則自動傳遞文檔、資訊或者任務(Task)。

【不使用工作流技術:】

從頭開始開發這個訂購流程的業務邏輯,我們需要:

- 每個活動點都需要開發互動頁面和背景處理程式

- 每個活動的流轉都需要硬性判斷下一步活動節點及其操作人

- 每次操作都需要維護業務資料和流程的相關資料

使用好處:

- 使用專門的流程資料系統,維護所有涉及流程流轉的資料。

- 提供“流程設計”工具,幫助使用者定義訂貨流程的模型,而且一般都提供了可視化的界面。

- 所有的流程都依靠流程引擎來處理,避免了需求更改與寫死之間沖突的産生。

- 工作流引擎還提供了衆多的API,可以很友善的将工作流的管理和業務操作完美結合。

工作流技術的優勢

  • 降低開發風險

    通過使用諸如活動、流轉、狀态、行為這樣的術語,使得業務分析師和開發人員使用同一種語言交談成為可能。優秀的流程設計模組化工具,甚至能使開發人員不必将使用者需求轉化成詳細設計文檔。

  • 流程實作的集中統一

    應對業務流程經常變化的情況,使用工作流技術的最大好處是使業務流程的實作代碼,不再散落在各式各樣的業務系統中。

  • 加速開發

    開發者不用再關注流程的參與者、活動節點的銜接、流轉控制……因為這些工作很多被工作流架構接管了。因而開發者開發起來更快、代碼出錯更少、系統更加容易維護。

  • 提升對疊代開發的支援

    如果系統中業務流程部分被寫死,就不容易更改,需求分析師就會花費很大的精力在開發前的業務分析中,并且希望一次成功。但可悲的是,在任何軟體項目開發中,這都很少能實作。工作流管理系統使得業務流程很容易部署和重新編排,業務流程相關的應用開發可以以一種“疊代/漸進”的方式推進,也就是說工作流技術在某種程度上支援“需求分析不必一次完全成功”。

工作流的技術特點

工作流隻管理流程,是不能完成業務操作的。換句話說,工作流是相對獨立的、通用的,與業務管理無直接關系。

比如費用報帳流程,工作流管理的是報帳的流程(誰申請,誰審批),費用報帳的業務(使用費用的原因,使用費用的時間,,)

工作流雖然與業務無直接關系,但是,在開發的時候,需要考慮和業務整合。

常見的工作流架構

Activiti、JBPM、OSWorkflow、ActiveBPEL、YAWL等。

Activiti的起源

Activiti是一套業務流程管理(BPM)架構,它覆寫了業務流管理、工作流、服務協助等領域,它是一個開源的(Apache許可2.0)、靈活的、易擴充的可執行流程語言架構。

Activiti是Alfresco軟體在2010年5月17日宣布啟動的一個開源項目,其創始人和首席架構師由業務流程管理BPM的專家 Tom Baeyens擔任。Tom Baeyens是JBoss jBPM的項目架構師。

提示:Jbpm4版本之後,該作者才做的Activiti,是以,Activiti很像jbpm4,理念又有點像hibernate。但是,jbpm5與4版本的差距比較大。

它是一項新的基于Apache許可的開源BPM平台,從基礎開始建構,提供支援新的BPMN 2.0标準。(直覺的認識就是XML)

Activiti提供了流程設計器,開發人員可以直接通過流程設計器直接畫出業務流程圖。

Activiti的持久層使用的Mybatis。(api将dao封裝了,無需會mybatis)

Activiti環境搭建

One minute version(官方Demo示範)

第一步:用管理者進去定制流程。

第二步:部署和啟動流程。

第三步:使用流程。

使用工作流系統需要三步:

1.畫流程圖(流程文檔xml定義)—管理者

2.部署到工作流的系統中—管理者

3.啟動流程,開始執行任務,直到任務結束。–使用者

建立Maven項目

Maven坐标(工作流引擎activiti-engine,日志實作slf4j-log4j12,資料庫驅動oracle,測試junit):

<properties>
        <activiti.version>5.19.0.2</activiti.version>
        <slf4j.version>1.7.5</slf4j.version>
        <oracle.version>10.2.0.4.0</oracle.version>
        <c3p0.version>0.9.1.2</c3p0.version>
        <junit.version>4.11</junit.version>
    </properties>
  <dependencies>
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-engine</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc14</artifactId>
        <version>${oracle.version}</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>
  </dependencies>
           

初始化Activiti資料庫

建立一個測試類:

/**
         * Activiti測試類
         */
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(locations="classpath:applicationContext.xml")
        public class ActivitiTest {

            //建立表:通過建立工廠(流程引擎:用來生成其他的服務api來具體操作)
            @Test
            public void testCreateTable(){
                //1.得到引擎的配置對象:單伺服器使用
                ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();

                //2.在引擎配置對象上設定相應的資料庫連接配接參數
                processEngineConfiguration.setJdbcDriver("oracle.jdbc.driver.OracleDriver");
                processEngineConfiguration.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:xe");
                processEngineConfiguration.setJdbcUsername("bos");
                processEngineConfiguration.setJdbcPassword("bos");

                //設定自動建表
                //三種參數值:
                //false:隻是檢查表結構,但不建立也不更新。适合已經有表的時候用
                //create-drop:啟動的時候檢查和建立表,引擎關閉的是的删除
                //true:檢查表結構,如果表存在,則建立,如果表結構不一緻,則更新。---常用
                processEngineConfiguration.setDatabaseSchemaUpdate(processEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

                //擷取工作流引擎對象(單例)
                ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
                System.out.println("====="+processEngine);


            }
        }
           

Activiti的核心

  • ACT_RE_*: ‘RE’表示repository。 這個字首的表包含了流程定義和流程靜态資源 (圖檔,規則,等等)。
  • ACT_RU_*: ‘RU’表示runtime。 這些運作時的表,包含流程執行個體,任務,變量,異步任務,等運作中的資料。 Activiti隻在流程執行個體執行過程中儲存這些資料, 在流程結束時就會删除這些記錄。 這樣運作時表可以一直很小速度很快。
  • ACT_ID_*: ‘ID’表示identity。 這些表包含身份資訊,比如使用者,組等等。
  • ACT_HI_*: ‘HI’表示history。 這些表包含曆史資料,比如曆史流程執行個體, 變量,任務等等。
  • ACT_GE_*: ‘GE’表示general。通用資料, 用于不同場景下,如存放資源檔案。
  • ACT_EVT_LOG:事件日志

ProcessEngine:流程引擎接口,是最核心的API類,其他的API類都由他而來。它是其他API産生的基礎!ProcessEngine對象,這是Activiti工作的核心。負責生成流程運作時的各種執行個體及資料、監控和管理流程的運作。

  • RepositoryService 流程定義管理 操作 ACT_RE_* 資料表
  • RuntimeService 流程執行個體管理 操作 ACT_RU_* 資料表
  • TaskService 任務管理 操作 ACT_RU_TASK 資料表
  • IdentitiService 認證管理 操作 ACT_ID_* 資料表
  • HistoryService 曆史記錄管理 操作 ACT_HI_* 資料表
  • ManagementService 定時任務管理,建立job,ACT_RU_JOB 資料表
  • FormService 表單管理,生成動态任務表單頁面,某個字段存的資料

maven坐标

<dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-engine</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
           

ApplicationContext.xml:

<!-- 流程引擎配置對象 -->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!-- 注入資料源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 自動建表 -->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>
    <!-- 流程引擎對象 -->
    <bean id="processEngine" factory-bean="processEngineConfiguration" factory-method="buildProcessEngine"/>
           

流程文檔定義—畫流程圖

流程id(非常重要-将來程式裡面叫key—流程定義的唯一辨別),必須英文.

添加辦理人:

Bpmn檔案解讀:

Activiti工作流-入門

流程定義管理

核心API

關于工作流的api,有個規律:要擷取某對象,都是createXxx;

如果是CreateXxx,擷取的就是xxx對象,該對象主要用來增删改對應的表。

如果是CreateXxxQuery,擷取的是xxxQuery對象,該對象主要用來查詢的。

加載流程文檔的時候,可以單獨加載文檔bpmn,工作流會自動生成一張圖檔存在資料庫。

但也可以兩個都加載,那麼工作流就不會自動生成圖檔,而使用你上傳的圖檔。

@RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(
                locations="classpath:applicationContext.xml")
        public class ActivitiTest {
            //注入倉庫Service
            @Autowired
            private RepositoryService repositoryService;

            //釋出流程:隻釋出流程圖,自動生成圖檔
            @Test
            public void deployment1(){
                Deployment deployment = repositoryService.createDeployment()//擷取釋出對象
                .addClasspathResource("diagrams/Leave.bpmn")//添加流程檔案
                .name("請假流程1")//釋出的名字
                .deploy();//釋出
                System.out.println("釋出的編号:"+deployment.getId());
                System.out.println("釋出的名稱:"+deployment.getName());
                System.out.println("釋出的時間:"+deployment.getDeploymentTime());
            }
            //釋出流程:釋出流程圖和圖檔--第一種方法
            @Test
            public void deployment21(){
                Deployment deployment = repositoryService.createDeployment()//擷取釋出對象
                        .addClasspathResource("diagrams/Leave.bpmn")//添加流程檔案
                        .addClasspathResource("diagrams/Leave.png")//添加流程圖檔
                        .name("請假流程21")//釋出的名字
                        .deploy();//釋出
                System.out.println("釋出的編号:"+deployment.getId());
                System.out.println("釋出的名稱:"+deployment.getName());
                System.out.println("釋出的時間:"+deployment.getDeploymentTime());
            }
            //釋出流程:釋出流程圖和圖檔--第二種方法
            @Test
            public void deployment22() throws FileNotFoundException{
                Deployment deployment = repositoryService.createDeployment()//擷取釋出對象
                        .addZipInputStream(new ZipInputStream(this.getClass().getClassLoader().getResourceAsStream("diagrams/Leave.zip")))
                        .name("請假流程22")//釋出的名字
                        .deploy();//釋出
                System.out.println("釋出的編号:"+deployment.getId());
                System.out.println("釋出的名稱:"+deployment.getName());
                System.out.println("釋出的時間:"+deployment.getDeploymentTime());
            }
        }
           

ApplicationContext.xml:

<!-- 流程控制的相關service -->
    <!-- 倉庫對象 -->
    <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"></bean>
           

工作流服務端自動生成的圖檔的亂碼問題解決方案:

解決方案1:

在流程引擎配置對象上面設定字型屬性:

<!-- 釋出流程生成圖檔是正常顯示中文 -->
        <property name="activityFontName" value="宋體"/>
        <property name="labelFontName" value="宋體"/>
           

解決方案2:

流程圖的圖檔在設計器中生成好,上傳到伺服器,不讓伺服器自動生成圖檔。

部署資訊查詢

//查詢部署表對象資料
        @Test
        public void queryDeployment(){
            List<Deployment> list = repositoryService.createDeploymentQuery()
            //條件查詢
                    .deploymentName("請假的流程部署")
                    .deploymentId("1")//根據id
                    .singleResult()//查詢出一條結果
                    .orderByDeploymenTime()//排序
                    .listPage(firstResult, maxResults)//分頁
                    .count()//統計
                    .list();
           

流程定義資訊查詢

@Test
        //查詢流程定義的表的資料
        public void queryProceeDefinition(){
            List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
    //      .processDefinitionKey(processDefinitionKey)//根據key來查詢
            .list();
           

流程圖檢視

//查詢流程圖
    @Test
    public void findProcessDefinitionDiagram() throws IOException{
        InputStream in = repositoryService.getProcessDiagram("LeaveProcess:1:4");
        OutputStream out = new FileOutputStream("z:/Leave.png");
        FileUtil.copyStream(in, out);
    }
           

流程定義的删除-流程銷毀

//删除流程定義(通過部署id)
        @Test
        public void deleteProcessDefinition(){
            repositoryService.deleteDeployment("1", true);
        }
           

級聯和不級聯。

場景:如果流程已經開啟了,如果不使用級聯,則會抛出異常!(原因:定義表有外鍵關聯它),此時隻能用級聯。

流程執行個體管理

流程執行個體的啟動

  • 根據流程定義的id來啟動:可以啟動指定的流程定義。
  • 根據流程定義的key來啟動:自動選擇版本号最高(最新)的流程定義來啟動
  • 根據消息的名字來啟動
//啟動流程執行個體
    @Test
    public void startProcessInstance(){
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("LeaveProcess");
    }
           

applicationContext.xml配置:

<!-- 運作時Service -->
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
           

流程執行個體的查詢

//查詢流程執行個體
    @Test
    public void queryProcessInstance(){
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery()
        .list();
    }
           

流程目前節點的坐标

//查詢活動節點坐标
    @Test
    public void queryActiveNodeZuobiao(){

        List<String> activeActivityIds = runtimeService.getActiveActivityIds("10001");
        for (String activeActivityId : activeActivityIds) {
            GraphicInfo graphicInfo1 = repositoryService.getBpmnModel("LeaveProcess:4:7504")
            .getGraphicInfo(activeActivityId);//某活動節點的坐标
        }
    }
           

流程執行個體的删除(強行終止)

//流程執行個體的删除
        @Test
        public void deleteProcessInstance(){
            runtimeService.deleteProcessInstance("LeaveProcess:4:7504", "不想請假了");
        }
           
  • 删除流程定義:可以級聯删除流程定義以及流程執行個體相關表資料。–管理者
  • 删除流程執行個體:隻删除流程執行個體相關(運作時)表的資料,對流程定義沒有影響。-流程啟動者

任務管理

個人任務查詢(待辦任務查詢)

//個人任務查詢
    @Test
    public void queryPersionTask(){
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee("張三")
                .list();
    }
           

個人任務辦理

//個人任務辦理
    @Test
    public void completePersonTask(){
        taskService.complete("12504");
    }
           

任務辦理完成

當end節點之前的節點辦理完成後,會自動完成end節點。目前流程執行個體都結束了。

繼續閱讀