基於Activiti擴展的工做流引擎OpenWebFlow

開源地址:https://github.com/bluejoe2008/openwebflow(歡迎star)java

1.    OpenWebFlow概述

OpenWebFlow是基於Activiti擴展的工做流引擎。Activiti (官方網站http://activiti.org/,代碼託管在https://github.com/Activiti/Activiti)是一個新興的基於 Apache 許可的支持 BPMN 2.0 標準的開源 BPM 產品,它是一個輕量級,可嵌入的 BPM 引擎,而且提供了功能豐富的開發和流程設計工具。OpenWebFlow與業務應用系統之間的關係以下圖所示。mysql

相對於Activiti,OpenWebFlow擴展的功能包括:git

1) 徹底接管了Activiti對活動(activity)權限的管理。
Activiti容許在設計model的時候指定每一個活動的執行權限,可是,業務系統可能須要根據實際狀況動態設置這些任務的執行權限(如:動態的Group)。OpenWebFlow徹底實現了與流程定義時期的解耦,即用戶對活動的訪問控制信息單獨管理(而不是在流程定義中預先寫死),這樣有利於動態調整權限,詳見自定義活動權限管理;github

2) 徹底接管了Activiti對用戶表(IDENTITY_XXX表)的管理。
在標準的工做流定義中,每一個節點能夠指定其候選人和候選用戶組,可是比較慘的是,Activiti綁架了用戶信息表的設計!這個是真正致命的,由於幾乎每一個業務系統都會屬於本身的用戶信息結構(包括User/Group/Membership),但不必定它存儲在Activiti喜歡的那個庫中,表的結構也不必定同樣,有的時候,某些信息(如:動態的Group)壓根兒就不採用表來存儲。OpenWebFlow剝離了用戶信息表的統一管理,客戶程序能夠忘掉Activiti的用戶表、羣組表、成員關係表,詳見自定義用戶成員關係管理;web

3) 容許運行時定義activity!
完全知足「中國特點」,並提供了安全的(同時也是優雅的)催辦、代辦、加簽(包括前加簽/後加籤)、自由跳轉(包括前進/後)、分裂節點等功能;spring

2.    快速上手

2.1    引入OpenWebFlow框架

2.1.1    以jar的方式引入OpenWebFlow

OpenWebFlow的發佈形式是一組正常的jar,其中openwebflow-core.XXX.jar包含了核心的工做流控制模塊,以及基於內存的管理器實現模塊。sql

此外,OpenWebFlow還提供了幾個jar:openwebflow-mgr-hibernate.XXX.jar,openwebflow-mgr-mybatis.XXX.jar,它們提供了管理器的SQL實現模塊,分別選取hibernate和mybatis做爲ORM模型。還有一個是openwebflow-mgr-test.XXX.jar,它包含了幾個測試類。數據庫

最新版本的下載地址:express

https://gitee.com/bluejoe/openwebflow/blob/master/openwebflow-core/target/openwebflow-core-0.9-SNAPSHOT.jar注意這些jar具備較多的依賴, https://gitee.com/bluejoe/openwebflow/tree/master/openwebflow-core/target/lib列舉了全部的依賴包以下:apache

  • activation-1.1.jar
  • activiti-bpmn-converter-5.16.1.jar
  • activiti-bpmn-layout-5.16.1.jar
  • activiti-bpmn-model-5.16.1.jar
  • activiti-crystalball-5.16.1.jar
  • activiti-engine-5.16.1.jar
  • activiti-explorer-5.16.1.jar
  • activiti-image-generator-5.16.1.jar
  • activiti-json-converter-5.16.1.jar
  • activiti-process-validation-5.16.1.jar
  • activiti-simple-workflow-5.16.1.jar
  • activiti-spring-5.16.1.jar
  • aopalliance-1.0.jar
  • commons-collections-2.0.jar
  • commons-dbcp-1.4.jar
  • commons-email-1.2.jar
  • commons-io-2.4.jar
  • commons-lang-2.6.jar
  • commons-lang3-3.3.2.jar
  • commons-logging-1.1.1.jar
  • commons-pool-1.5.4.jar
  • dcharts-widget-0.10.0.jar
  • groovy-all-2.1.3.jar
  • h2-1.3.168.jar
  • hamcrest-core-1.3.jar
  • imgscalr-lib-4.2.jar
  • jackson-annotations-2.2.3.jar
  • jackson-core-2.2.3.jar
  • jackson-databind-2.2.3.jar
  • javaGeom-0.11.1.jar
  • jcl-over-slf4j-1.7.6.jar
  • jgraphx-1.10.4.1.jar
  • joda-time-2.1.jar
  • junit-4.12.jar
  • log4j-1.2.17.jar
  • mail-1.4.1.jar
  • mybatis-3.2.8.jar
  • mybatis-spring-1.2.2.jar
  • mysql-connector-java-5.1.32.jar
  • servlet-api-2.5.jar
  • slf4j-api-1.7.2.jar
  • slf4j-jdk14-1.7.2.jar
  • slf4j-log4j12-1.7.6.jar
  • spring-aop-3.2.4.RELEASE.jar
  • spring-beans-3.2.4.RELEASE.jar
  • spring-context-3.2.4.RELEASE.jar
  • spring-core-3.2.4.RELEASE.jar
  • spring-expression-3.2.4.RELEASE.jar
  • spring-jdbc-3.2.4.RELEASE.jar
  • spring-orm-3.2.4.RELEASE.jar
  • spring-tx-3.2.4.RELEASE.jar
  • spring-web-3.2.4.RELEASE.jar
  • spring-webmvc-3.2.4.RELEASE.jar
  • vaadin-6.8.8.jar

2.1.2    以maven的方式引入OpenWebFlow

以maven的方式引入OpenWebFlow比較簡單,pom.xml中的依賴項寫成:

<dependency>
     <groupId>org.openwebflow</groupId>
     <artifactId>openwebflow-core </artifactId>
     <version>0.9-SNAPSHOT</version>
</dependency>

在引入依賴項以前可能須要先在本地倉庫中安裝OpenWebFlow項目。具體操做是在eclipse中選擇OpenWebFlow項目,【右鍵菜單】【Maven】【install】。

2.2    配置文件

準備SpringIoC配置文件,分別是settings.properties 、activiti.cfg.core.xml和activiti.cfg.mem.xml(或者是activiti.cfg.sql.XXX.xml):

  • settings.properties:公共屬性設置
  • activiti.cfg.core.xml:用以配置工做流引擎的基本配置信息;
  • activiti.cfg.mem.xml:用以定義一些用以支持OpenWebFlow工做的manager,注意名字中的mem,它暗示着僅提供了那些manager的基於內存實現的版本,相似的配置文件還能夠是activiti.cfg.sql.XXX.xml;

2.2.1    settings.properties

settings.properties文件是一個正常的屬性文件,用以spring IOC文件加載。以下是一個屬性文件的內容:

mail.host=smtp.bluejoe.cn
mail.port=25
mail.username=sdb-support@cnic.cn
mail.password=sdbsupport
mail.from=sdb-support@cnic.cn
model.dir=../models
alarm.mail.template=classpath:/alarm-template.txt
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.hbm2ddl.auto=none
activitidb.url=jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000
activitidb.driver=org.hDriver
activitidb.username=sa
activitidb.password=
owfdb.url=jdbc:mysql://localhost:3306/openwebflow?useUnicode=true&amp;characterEncoding=UTF-8
owfdb.driver=com.mysql.jdbc.Driver
owfdb.username=root
owfdb.password=1

各屬性的含義以下:

屬性名

示例值

含義

mail.host

smtp.bluejoe.cn

催辦郵件發件服務器主機地址

mail.port

25

催辦郵件發件服務器端口號

mail.username

sdb-support@cnic.cn

催辦郵件發件帳號名

mail.password

sdbsupport

催辦郵件發件帳號密碼

mail.from

sdb-support@cnic.cn

催辦郵件發件人

model.dir

../models

自動加載的BPMN模型路徑

alarm.mail.template

classpath:/alarm-template.txt

催辦郵件正文模板

hibernate.dialect

org.hibernate.dialect.MySQLDialect

Hibernate方言

hibernate.hbm2ddl.auto

none

Hibernate DDL設置

activitidb.url

jdbc:h2:mem:activiti;DB_CLOSE_DELAY

Activiti數據庫JDBC URL

activitidb.driver

org.h2.Driver

Activiti數據庫JDBC驅動

activitidb.username

sa

Activiti數據庫帳號名

activitidb.password

 

Activiti數據庫帳號密碼

owfdb.url

jdbc:mysql://localhost:3306/openwebflow?useUnicode

OpenWebFlow數據庫JDBC URL

owfdb.driver

com.mysql.jdbc.Driver

OpenWebFlow數據庫JDBC驅動

owfdb.username

root

OpenWebFlow數據庫帳號名

owfdb.password

1

OpenWebFlow數據庫帳號密碼

2.2.2    activiti.cfg.core.xml配置

activiti.cfg.core.xml的配置與Activiti要求的那個配置文件有點類似,但能夠多一些內容,以下是個例子:

<!-- 工做流核心數據庫配置 -->
<bean id="activitiDataSource" class="org.apache.commons.dbcp.BasicDataSource"
	destroy-method="close">
	<property name="driverClassName" value="${activitidb.driver}" />
	<property name="url" value="${activitidb.url}" />
	<property name="username" value="${activitidb.username}" />
	<property name="password" value="${activitidb.password}" />
	<property name="initialSize" value="20" />
	<property name="maxActive" value="50" />
	<property name="maxIdle" value="20" />
	<property name="minIdle" value="10" />
</bean>

<!-- 任務催辦配置 -->
<bean id="myTaskAlarmService" class="org.openwebflow.alarm.impl.TaskAlarmServiceImpl">
	<!-- 截止日期提早量 -->
	<property name="periodInAdvance" value="P2D" />
	<!-- 設置消息通知機制 -->
	<property name="messageNotifier">
		<!-- 採用郵件發送 -->
		<bean class="org.openwebflow.alarm.impl.MailMessageNotifier">
			<property name="subjectTemplate" value="請儘快處理#{'$'}{task.name}任務" />
			<property name="messageTemplateResource" value="${alarm.mail.template}" />
			<property name="mailSender">
				<bean class="org.openwebflow.alarm.impl.MailSender">
					<property name="serverHost" value="${mail.host}" />
					<property name="serverPort" value="${mail.port}" />
					<property name="authUserName" value="${mail.username}" />
					<property name="authPassword" value="${mail.password}" />
					<property name="mailFrom" value="${mail.from}" />
				</bean>
			</property>
		</bean>
	</property>
	<property name="membershipManager" ref="myMembershipManager" />
	<property name="userDetailsManager" ref="myUserDetailsManager" />
	<property name="taskNotificationManager" ref="myTaskNotificationManager" />
</bean>

<bean id="transactionManager"
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="activitiDataSource" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<!-- 配置對象 -->
<bean id="processEngineConfiguration" class="org.openwebflow.cfg.ProcessEngineConfigurationEx">
	<property name="dataSource" ref="activitiDataSource" />
	<property name="transactionManager" ref="transactionManager" />
	<property name="databaseSchemaUpdate" value="true" />
	<property name="jobExecutorActivate" value="false" />
	<property name="startEngineEventListeners">
		<list>
			<!-- 加載自定義表單元素類型 -->
			<bean class="org.openwebflow.cfg.LoadDummyFormTypes">
				<property name="typeNames" value="user" />
			</bean>
			<!-- 自定義成員關係管理 -->
			<bean class="org.openwebflow.cfg.ReplaceMembershipManager">
				<property name="customMembershipManager" ref="myMembershipManager" />
			</bean>
			<!-- 自定義活動權限管理 -->
			<bean class="org.openwebflow.cfg.ReplaceTaskAssignmentHandler">
				<!-- 受權處理器列表,會組成一個鏈,越靠後優先級越高(越靠外) -->
				<property name="handlers">
					<list>
						<!-- 自定義受權項列表 -->
						<bean
							class="org.openwebflow.assign.permission.ActivityPermissionAssignmentHandler">
							<property name="activityPermissionManager" ref="myActivityPermissionManager" />
						</bean>
						<!-- 容許受權代理 -->
						<bean
							class="org.openwebflow.assign.delegation.TaskDelagationAssignmentHandler">
							<property name="delegationManager" ref="myDelegationManager" />
							<property name="membershipManager" ref="myMembershipManager" />
							<property name="hideDelegated" value="false" />
						</bean>
					</list>
				</property>
			</bean>
			<!-- 自動導入流程模型 -->
			<bean class="org.openwebflow.cfg.ImportDefinedProcessModels">
				<property name="modelDir" value="${model.dir}" />
			</bean>
			<!-- 啓動催辦管理器 -->
			<bean class="org.openwebflow.cfg.StartTaskAlarmService">
				<property name="taskAlarmService" ref="myTaskAlarmService" />
				<property name="runOnStartup" value="false" />
			</bean>
			<!-- 加載自定義activity -->
			<bean class="org.openwebflow.cfg.LoadRuntimeActivityDefinitions">
				<property name="activityDefinitionManager" ref="myActivityDefinitionManager" />
			</bean>
		</list>
	</property>
</bean>

<!-- processEngine -->
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
	<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>

<!-- 工做流流轉服務對象工廠 -->
<bean class="org.openwebflow.ctrl.impl.DefaultTaskFlowControlServiceFactory" />

<!-- processEngineTool -->
<bean id="processEngineTool" class="org.openwebflow.util.ProcessEngineTool" />

其中processEngineConfiguration是加強型的工做流引擎配置對象,能夠設置自定義用戶羣組成員關係管理策略自定義活動權限管理策略等。

完整的例子參見:https://gitee.com/bluejoe/openwebflow/blob/master/openwebflow-test/src/test/resources/activiti.cfg.core.xml

2.2.3     activiti.cfg.mem.xml配置

在activiti.core.xml中會用到一些manager,activiti.mem.xml定義基於內存的manager實現,默認的activiti.mem.xml內容以下:

<!-- 自定義成員關係管理 -->
<bean id="myMembershipManager" class="org.openwebflow.mgr.mem.InMemoryMembershipManager" />
<bean id="myUserDetailsManager" class="org.openwebflow.mgr.mem.InMemoryUserDetailsManager" />

<!-- 自定義的活動權限表管理 -->
<bean id="myActivityPermissionManager"
	class="org.openwebflow.mgr.mem.InMemoryActivityPermissionManager" />
	
<!-- 代理關係管理 -->
<bean id="myDelegationManager" class="org.openwebflow.mgr.mem.InMemoryDelegationManager" />
	
<!-- 自定義的動態自定義活動管理 -->
<bean id="myActivityDefinitionManager"
	class="org.openwebflow.mgr.mem.InMemoryRuntimeActivityDefinitionManager" />

<bean id="myTaskNotificationManager" class="org.openwebflow.mgr.mem.InMemoryTaskNotificationManager" />

這裏面定義了6個manager:

Manager類別

含義

myMembershipManager

自定義成員關係管理

myUserDetailsManager

自定義用戶詳細信息管理

myActivityPermissionManager

自定義的活動權限表管理

myDelegationManager

代理關係管理

myActivityDefinitionManager

自定義的動態自定義活動管理

myTaskNotificationManager

任務通知信息管理

完整的例子參見:https://gitee.com/bluejoe/openwebflow/blob/master/openwebflow-test/src/test/resources/activiti.cfg.mem.xml

與activiti.cfg.core.xml相似的可替代文件爲activiti.cfg.sql.hibernate.xml和activiti.cfg.sql.mybatis.xml。

2.2.4    activiti.cfg.sql.hibernate.xml配置

activiti.sql.hibernate.xml提供基於SQL的manager實現,採用的ORM框架爲Hibernate 4。

各manager的定義以下:

<!-- 代理記錄管理 -->
<bean id="myDelegationManager"
	class="org.openwebflow.mgr.hibernate.service.SqlDelegationManager" />
<!-- 自定義成員關係管理 -->
<bean id="myMembershipManager"
	class="org.openwebflow.mgr.hibernate.service.SqlMembershipManager" />
<!-- 自定義用戶表 -->
<bean id="myUserDetailsManager"
	class="org.openwebflow.mgr.hibernate.service.SqlUserDetailsManager" />
<!-- 自定義的活動權限表管理 -->
<bean id="myActivityPermissionManager"
	class="org.openwebflow.mgr.hibernate.service.SqlActivityPermissionManager" />
<!-- 自定義的動態自定義活動管理 -->
<bean id="myActivityDefinitionManager"
	class="org.openwebflow.mgr.hibernate.service.SqlRuntimeActivityDefinitionManager" />
<bean id="myTaskNotificationManager"
	class="org.openwebflow.mgr.hibernate.service.SqlTaskNotificationManager" />

此外,還須要定義數據源、Hibernate Session工廠,以及事務。

<!-- 數據庫腳本見openwebflow.sql -->
<bean id="owfDataSource" class="org.apache.commons.dbcp.BasicDataSource"
	destroy-method="close">
	<property name="driverClassName" value="${owfdb.driver}" />
	<property name="url" value="${owfdb.url}" />
	<property name="username" value="${owfdb.username}" />
	<property name="password" value="${owfdb.password}" />
	<property name="initialSize" value="20" />
	<property name="maxActive" value="50" />
	<property name="maxIdle" value="20" />
	<property name="minIdle" value="10" />
</bean>

<!-- 配置SessionFactory -->
<bean id="sessionFactory"
	class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
	<property name="dataSource" ref="owfDataSource" />
	<property name="hibernateProperties">
		<props>
			<prop key="hibernate.dialect">${hibernate.dialect}</prop>
			<!-- <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop> -->
			<!-- 服務啓動經過實體建立數據庫表信息 -->
			<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
			<prop key="hibernate.show_sql">true</prop>
			<prop key="hibernate.format_sql">true</prop>
			<prop key="hibernate.jdbc.batch_size">20</prop>
			<prop key="hibernate.connection.release_mode">auto</prop>
			<prop key="hibernate.autoReconnect">false</prop>
			<prop key="hibernate.connection.autocommit">true</prop>
			<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
			<prop key="hibernate.jdbc.use_streams_for_binary">true</prop>
			<prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext
			</prop>
			<!--解決weblogic沒法使用hql的問題 -->
			<prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
		</props>
	</property>

	<!-- 自動掃描備註解的實體 -->
	<property name="packagesToScan">
		<list>
			<value>org.openwebflow.mgr.hibernate.entity</value>
		</list>
	</property>
</bean>

<!-- 配置一個事務管理器 -->
<bean id="transactionManager"
	class="org.springframework.orm.hibernate4.HibernateTransactionManager">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

採用HibernateORM,openwebflow-mgr-hibernate的代碼結構以下:

其中,DAO類、實體類、服務類分別存放在dao、entity、service包下面。service類的事務聲明以及entity的映射皆採起註解方式。

完整的例子參見:https://gitee.com/bluejoe/openwebflow/blob/master/openwebflow-test/src/test/resources/activiti.cfg.sql.hibernate.xml

2.2.5     activiti.cfg.sql.mybatis.xml配置

activiti.sql.mybatis.xml提供基於SQL的manager實現,採用的ORM框架爲mybatis 3。

各manager的定義以下:

<!-- 代理記錄管理 -->
<bean id="myDelegationManager"
	class="org.openwebflow.mgr.mybatis.service.SqlDelegationManager" />
<!-- 自定義成員關係管理 -->
<bean id="myMembershipManager"
	class="org.openwebflow.mgr.mybatis.service.SqlMembershipManager" />
<!-- 自定義用戶表 -->
<bean id="myUserDetailsManager"
	class="org.openwebflow.mgr.mybatis.service.SqlUserDetailsManager" />
<!-- 自定義的活動權限表管理 -->
<bean id="myActivityPermissionManager"
	class="org.openwebflow.mgr.mybatis.service.SqlActivityPermissionManager" />
<!-- 自定義的動態自定義活動管理 -->
<bean id="myActivityDefinitionManager"
	class="org.openwebflow.mgr.mybatis.service.SqlRuntimeActivityDefinitionManager" />
<bean id="myTaskNotificationManager"
	class="org.openwebflow.mgr.mybatis.service.SqlTaskNotificationManager" />

此外,還須要定義數據源、SqlSessionFactory,以及事務。

<!-- 數據庫腳本見openwebflow.sql -->
<bean id="owfDataSource" class="org.apache.commons.dbcp.BasicDataSource"
	destroy-method="close">
	<property name="driverClassName" value="${owfdb.driver}" />
	<property name="url" value="${owfdb.url}" />
	<property name="username" value="${owfdb.username}" />
	<property name="password" value="${owfdb.password}" />
	<property name="initialSize" value="20" />
	<property name="maxActive" value="50" />
	<property name="maxIdle" value="20" />
	<property name="minIdle" value="10" />
</bean>

<!-- 建立SqlSessionFactory,同時指定數據源-->
<bean id="owlSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="owfDataSource" />
</bean>

<!-- 配置一個事務管理器 -->
<bean id="transactionManager"
	class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="owfDataSource" />
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

採用Mybatis ORM,openwebflow-mgr-mybatis的代碼結構以下:

其中,Mapper接口、實體類、服務類分別存放在mapper、entity、service包下面。service類的事務聲明以及Mapper的映射皆採起註解方式。

完整的例子參見:https://gitee.com/bluejoe/openwebflow/blob/master/openwebflow-test/src/test/resources/activiti.cfg.sql.mybatis.xml

2.3    數據庫設計

首先,Activiti引擎自己須要用到一系列的數據表,設置好數據源後,Activiti會自動生成這些表。

Activiti的表都以ACT_開頭,第二部分是表示表的用途的兩個字母標識。用途也和服務的API對應。

  • ACT_RE_*: 'RE'表示repository。這個前綴的表包含了流程定義和流程靜態資源(圖片,規則,等等)。
  • ACT_RU_*: 'RU'表示runtime。這些運行時的表,包含流程實例,任務,變量,異步任務,等運行中的數據。 Activiti只在流程實例執行過程當中保存這些數據, 在流程結束時就會刪除這些記錄。這樣運行時表能夠一直很小速度很快。
  • ACT_ID_*: 'ID'表示identity。這些表包含身份信息,好比用戶,組等等。
  • ACT_HI_*: 'HI'表示history。這些表包含歷史數據,好比歷史流程實例,變量,任務等等。
  • ACT_GE_*: 通用數據, 用於不一樣場景下。

OpenWebFlow爲一系列manager提供了基於數據庫的實現,須要用到一些數據表,對應的建庫腳本參見https://gitee.com/bluejoe/openwebflow/tree/master/doc目錄下的:

  • openwebflow-mysql4.sql:MySQL4腳本
  • openwebflow-mysql5.sql:MySQL5腳本
  • openwebflow-sqlserver2008.sql:SQLServer2008腳本
  • openwebflow-oracle10g.sql:Oracle腳本

其中共定義了6張表格:

  • OWF_ACTIVITY_CREATION:用以存儲自定義的活動定義信息
  • OWF_ACTIVITY_PERMISSION:用以存儲自定義的活動權限信息
  • OWF_DELEGATION:用以存儲用戶代理信息
  • OWF_NOTIFICATION:用以存儲催辦通知記錄
  • OWF_MEMBERSHIP:用以存儲用戶組成員關係
  • OWF_USER:用以存儲用戶信息

注意:OWF_MEMBERSHIP和OWF_USER僅爲測試使用,建議用戶使用本身的數據表(OpenWebFlow自己努力的一個方向就是將用戶及成員關係管理與工做流引擎剝離開),幷包裝本身的Manager。

2.4    使用ApplicationContext定義的bean

採用Spring IoC框架加載完XML配置文件以後,ApplicationContext中會包含以下變量,可供客戶程序使用:

  • processEngine:工做流引擎對象,標準的Activiti對象
  • processEngineTool:針對processEngine提供了一些工具方法
  • defaultTaskFlowControlServiceFactory:任務流控制器的工廠對象
  • repositoryService:提供了管理和控制發佈包和流程定義的操做
  • RuntimeService:負責啓動一個流程定義的新實例
  • TaskService:與任務相關相關的操做
  • IdentityService:管理(建立,更新,刪除,查詢...)羣組和用戶
  • FormService:提供了啓動表單和任務表單兩個概念
  • HistoryService:提供了Activiti引擎手機的全部歷史數據
  • ManagementService:能夠查詢數據庫的表和表的元數據

以下是使用OpenWebFlow的示例代碼,能夠看出來與Activiti的用法徹底一致:

ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:activiti.cfg.mem.xml");  
ProcessEngineTool tool = ctx.getBean(ProcessEngineTool.class);  
ProcessEngine processEngine = tool.getProcessEngine();  
// 啓動流程實例  
ProcessInstance instance = processEngine.getRuntimeService().startProcessInstanceByKey("test1");  
TaskService taskService = processEngine.getTaskService();  
//會自動跳轉到第一個task  
//management能夠訪問該task  
Assert.assertEquals(1, taskService.createTaskQuery().taskCandidateGroup("management").count());  

 

2.5    運行測試用例

在openwebflow-test項目源代碼中,用戶能夠找到一組測試用例來對工做流引擎的功能進行測試,它們分別是:

  • MemProcessEngineTest:基於內存的manager測試
  • SqlHibernateProcessEngineTest:基於hibernateORM的manager測試
  • SqlMybatisProcessEngineTest:基於mybatisORM的manager測試

以上3個測試類都繼承於AbstractProcessEngineTest:

AbstractProcessEngineTest提供了測試方法:

方法摘要

void

testActivityPermission() 
          
測試流程動態受權

 void

testAlarm() 
          
測試催辦功能

 void

testCachedDefinitions() 
          
測試TaskDefinition

 void

testDelegation() 
          
測試代理功能

 void

testInsertTasksAfter() 
          
測試後加籤

 void

testInsertTasksBefore() 
          
測試前加簽

 void

testInsertTasksWithPersistence() 
          
測試加簽功能的持久化

 void

testModelDeployment() 
          
測試流程模型部署

 void

testMove() 
          
測試自由跳轉

 void

testMultiInstancesLoop() 
          
測試多實例節點

 void

testSplit() 
          
測試測試節點分裂

其中爲了配合測試設計了一個複雜的流程(models/test2.bpmn)如圖所示:

 

選擇指定的測試單元(如:MemProcessEngineTest),以「JUnit測試」的方式運行(Run As…),便可觀察到測試結果:

 

也能夠選擇運行測試套件AllTests:

 

3.    熟悉OpenWebFlow代碼

3.1    下載源碼

用戶能夠下載OpenWebFlow的zip包,下載地址爲:https://gitee.com/bluejoe/openwebflow/archive/master.zip

也能夠經過git方式獲取到最新源碼,git資源庫地址爲:https://gitee.com/bluejoe/openwebflow.git

3.2    代碼結構

OpenWebFlow源碼包含5個maven工程,其中openwebflow工程是父工程,它聲明瞭包含openwebflow-core、openwebflow-mgr-hibernate、openwebflow-mgr-mybatis、openwebflow-test等4個model。

  • openwebflow-core:核心工程,包含OpenWebFlow擴展引擎的全部核心內容、以及基於內存的manager實現。
  • openwebflow-mgr-hibernate:依賴於openwebflow-core,提供了基於數據庫的manager實現,ORM框架採用Hibernate。
  • openwebflow-mgr-mybatis:依賴於openwebflow-core,提供了基於數據庫的manager實現,ORM框架採用MyBatis。
  • openwebflow-test:依賴於以上項目,提供了測試用例,包括配置文件、測試類等。

3.3    build項目

獲取到的項目源碼能夠採用Maven完成build和install,以下爲build截圖:

 

3.4    核心對象

3.4.1    ProcessEngineConfigurationEx

ProcessEngineConfigurationEx是針對Activiti提供的ProcessEngineConfiguration類的派生類:

 

兩者大部分參數徹底一致,惟一不一樣的是,ProcessEngineConfigurationEx提供了一個屬性:startEngineEventListeners。

startEngineEventListeners用以定義工做流引擎啓動的時候須要同時啓動的其它任務,startEngineEventListeners是個List,所以能夠隨意增長新的任務,默認的core.xml中會加載以下任務:LoadDummyFormTypes、ReplaceMembershipManager、ReplaceTaskAssignmentHandler、ImportDefinedProcessModels、StartTaskAlarmService、LoadRuntimeActivityDefinitions。各任務及類屬性列表以下:

任務類

用途

屬性名

屬性含義

LoadDummyFormTypes

加載一些無用的Form類型,用以屏蔽一些自定義Form帶來的錯誤

typeNames

須要屏蔽的Form類型名,以;分隔,如:user

ReplaceMembershipManager

直接接管用戶組成員關係

customMembershipManager

指定客戶程序自定義的管理器

ReplaceTaskAssignmentHandler

接管Activiti的用戶權限管理,若是你想實現動態的節點權限分配,那必需要打開它。

handlers

定義一個受權處理器列表,值類型爲List,運行時刻各受權處理器列表會組成一個鏈,越靠後優先級越高(越靠外)

ImportDefinedProcessModels

自動從指定目錄導入BPMN模型

modelDir

用以指定模型的路徑,能夠是classpath:等路徑

StartTaskAlarmService

啓動任務催辦服務

taskAlarmService

設置催辦服務對象

 

 

runOnStartup

是否一開始就啓動(默認爲true)

LoadRuntimeActivityDefinitions

加載運行時的節點定義,主要用來支持在運行時刻定義新的節點

activityDefinitionManager

指定節點定義管理器

3.4.2    ProcessEngineTool

ProcessEngineTool提供了一些工具方法,這些方法的功能通常很難經過ProcessEngine直接拿到:

方法摘要

 org.activiti.engine.repository.Model

createNewModel(java.lang.String name, java.lang.String description) 
          
建立一個空白的Model對象

 org.activiti.engine.repository.Deployment

deployModel(java.lang.String modelId) 
          
部署一個已註冊的model

 org.activiti.engine.impl.pvm.process.ActivityImpl

getActivity(java.lang.String processDefId, java.lang.String activityId) 
          
獲取指定名字的活動

 java.util.Map<java.lang.String,java.lang.Object>

getHistoricProcessVariables(java.lang.String processId) 
          
獲取指定歷史流程的變量列表

 org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity

getProcessDefinition(java.lang.String processDefId) 
          
獲取指定ID的流程定義

 org.activiti.engine.ProcessEngine

getProcessEngine() 
           

 void

grantPermission(org.activiti.engine.impl.pvm.process.ActivityImpl activity, java.lang.String assigneeExpression, java.lang.String candidateGroupIdExpressions, java.lang.String candidateUserIdExpressions) 
          
設置指定活動的用戶權限,包括欽定用戶、候選用戶、候選組

 void

grantPermission(java.lang.String processDefId, java.lang.String activityId, java.lang.String assigneeExpression, java.lang.String candidateGroupIdExpressions, java.lang.String candidateUserIdExpressions) 
          
設置指定活動的用戶權限,包括欽定用戶、候選用戶、候選組

 void

setProcessEngine(org.activiti.engine.ProcessEngine processEngine) 

3.4.3    各類Utils

OpenWebFlow提供了一些常見的工具類,以下所示:

類摘要

CloneUtils

實現對象的克隆功能

ExpressionUtils

實現常見類型的expression的包裝和轉換

IdentityUtils

實現用戶、成員關係等相關操做

ModelUtils

包裝了對BPMN模型的部署、註冊等功能

ProcessDefinitionUtils

流程定義相關操做的封裝

3.4.4    TaskFlowControlService

TaskFlowControlService用以實現流程的自由控制,它提供的方法以下:

方法摘要

 org.activiti.engine.impl.pvm.process.ActivityImpl[]

insertTasksAfter(java.lang.String targetTaskDefinitionKey, java.lang.String... assignees) 
          
後加籤

 org.activiti.engine.impl.pvm.process.ActivityImpl[]

insertTasksBefore(java.lang.String targetTaskDefinitionKey, java.lang.String... assignees) 
          
前加簽

 void

moveBack() 
          
後退一步

 void

moveBack(org.activiti.engine.impl.persistence.entity.TaskEntity currentTaskEntity) 
          
後退至指定活動

 void

moveForward() 
          
前進一步

 void

moveForward(org.activiti.engine.impl.persistence.entity.TaskEntity currentTaskEntity) 
          
前進至指定活動

 void

moveTo(java.lang.String targetTaskDefinitionKey) 
          
跳轉(包括回退和向前)至指定活動節點

 void

moveTo(java.lang.String currentTaskId, java.lang.String targetTaskDefinitionKey) 
          
跳轉(包括回退和向前)至指定活動節點

 void

moveTo(org.activiti.engine.impl.persistence.entity.TaskEntity currentTaskEntity, java.lang.String targetTaskDefinitionKey) 
          
跳轉(包括回退和向前)至指定活動節點

 org.activiti.engine.impl.pvm.process.ActivityImpl

split(java.lang.String targetTaskDefinitionKey, boolean isSequential, java.lang.String... assignees) 
          
分裂某節點爲多實例節點

 org.activiti.engine.impl.pvm.process.ActivityImpl

split(java.lang.String targetTaskDefinitionKey, java.lang.String... assignee) 
          
分裂某節點爲多實例節點

TaskFlowControlService須要一個TaskFlowControlServiceFactory來建立,能夠從applicationcontext中獲取到該工廠對象。

4.    核心功能的設計與使用【略】

5.    使用管理器接口實現自定義擴展

OpenWebFlow須要用戶提供6類管理器的接口,它們分別是:

  • RuntimeActivityDefinitionManager:負責獲取活動的定義信息,用以支持運行時期的新建活動
  • ActivityPermissionManager:負責獲取活動的權限設置信息
  • TaskNotificationManager:負責存取任務催辦通知信息
  • DelegationManager:負責獲取用戶的代理信息
  • UserDetailsManager:負責獲取用戶的信息(包括E-mail、暱稱、手機號等),主要用以發送催辦通知
  • IdentityMembershipManager:負責獲取用戶組成員關係,獲取某用戶的候選任務隊列時,須要經過用戶名獲取到用戶組

除了這些Manager以外,用戶會發現OpenWebFlow還提供了一系列的ManagerEx接口:

  • ActivityPermissionManagerEx:負責保存活動的權限設置信息
  • TaskNotificationManagerEx:負責保存任務催辦通知信息
  • DelegationManagerEx:負責保存用戶的代理信息
  • UserDetailsManagerEx:負責保存用戶的信息
  • IdentityMembershipManagerEx:負責保存用戶組成員關係

能夠簡單的認爲,Manager接口主要用以信息讀取(read),ManagerEx接口主要用以信息寫入(write),注意使用OpenWebFlow引擎時,ManagerEx不是必需要提供相應實現的!OpenWebFlow引擎的全部操做只會調用到Manager而非ManagerEx,提供ManagerEx的惟一用處是爲了測試(若是沒有寫入,讀取返回的永遠是空白,測試就沒法正常進行了)。

5.1   活動定義管理

客戶程序每每須要在運行時候調整某個工做流的流程,如:讓活動step5執行完以後跳轉至step2,這樣的操做須要建立一個新的路徑,爲了保證後續流程的正常執行(特別是應用重啓以後),這樣的路徑須要保存和加載。

5.1.1    RuntimeActivityDefinitionManager

RuntimeActivityDefinitionManager包含以下方法:

方法摘要

java.util.List <RuntimeActivityDefinitionEntity>

list() 
          獲取全部的活動定義信息,引擎會在啓動的時候加載這些活動定義並進行註冊

 void

removeAll() 
          刪除全部活動定義

 void

save(RuntimeActivityDefinitionEntity entity) 
          新增一條活動定義的信息

5.1.2    RuntimeActivityDefinitionEntity

RuntimeActivityDefinitionEntity對應於一條活動的定義信息:

 

方法摘要

 void

deserializeProperties() 
          
反序列化PropertiesText到Map

 java.lang.String

getFactoryName() 
          
獲取工廠名

 java.lang.String

getProcessDefinitionId() 
          
獲取流程定義的ID

 java.lang.String

getProcessInstanceId() 
          
獲取流程實例的ID

 java.lang.String

getPropertiesText() 
          
獲取PropertiesText,它是一個JSON字符串

<T> T

getProperty(java.lang.String name) 
          
獲取指定的屬性值

 void

serializeProperties() 
          
序列化Map至PropertiesText

 void

setFactoryName(java.lang.String factoryName) 
          
設置工廠名

 void

setProcessDefinitionId(java.lang.String processDefinitionId) 
          
設置流程定義ID

 void

setProcessInstanceId(java.lang.String processInstanceId) 
          
設置流程實例ID

 void

setPropertiesText(java.lang.String propertiesText) 
          
設置PropertiesText

<T> void

setProperty(java.lang.String name, T value) 

5.2    活動權限管理

5.2.1    ActivityPermissionManager

活動權限的管理接口爲ActivityPermissionManager,它的定義以下:

方法摘要

 ActivityPermissionEntity

load(java.lang.String processDefinitionId, java.lang.String taskDefinitionKey, boolean addOrRemove) 
          
獲取指定活動的權限定義信息

5.2.2    ActivityPermissionEntity

很是簡單,它只須要一個方法,該方法返回一個ActivityPermissionEntity,該實體的定義以下:

方法摘要

 java.lang.String

getAssignee() 
          
獲取直接受權人

 java.lang.String[]

getGrantedGroupIds() 
          
獲取候選組列表

 java.lang.String[]

getGrantedUserIds() 
          
獲取候選用戶列表

5.2.3    ActivityPermissionManagerEx

ActivityPermissionManagerEx實現對活動權限表的「寫」操做:

方法摘要

void

removeAll() 
          
刪除全部權限定義信息

 void

save(java.lang.String processDefId, java.lang.String taskDefinitionKey, java.lang.String assignee, java.lang.String[] candidateGroupIds, java.lang.String[] candidateUserIds) 
          
保存一條權限定義信息

5.3    任務催辦通知管理

5.3.1    TaskNotificationManager

TaskNotificationManager負責讀取和設置任務催辦的狀態,該接口也很簡單:

方法摘要

 boolean

isNotified(java.lang.String taskId) 
          
判斷指定任務是否通知過

 void

setNotified(java.lang.String taskId) 
          
設置指定任務的通知狀態

能夠理解成TaskNotificationManager維護了一個隊列,記錄了每一個任務的通知狀態(已通知爲true,未通知爲false)。

5.3.2    TaskNotificationManagerEx

TaskNotificationManagerEx實現了對通知記錄的「寫」操做:

方法摘要

 void

removeAll() 
          
刪除全部通知記錄

5.4    用戶代理關係管理

5.4.1    DelegationManager

DelegationManager用以維護用戶之間的代理關係。接口包含2個方法:

方法摘要

 java.lang.String[]

getDelegates(java.lang.String delegated) 
          
獲取指定用戶的代理人列表

 java.util.List<DelegationEntity>

listDelegationEntities() 
          
獲取全部的代理信息列表,引擎會在啓動的時候加載

5.4.2    DelegationEntity

DelegationEntity描述一條代理關係:

方法摘要

 java.lang.String

getDelegate() 
          
獲取當前代理記錄的代理人

 java.lang.String

getDelegated() 
          
獲取當前代理記錄的被代理人

5.4.3    DelegationManagerEx

DelegationManagerEx用以實現對代理記錄的「寫」操做:

方法摘要

 void

removeAll() 
          
刪除全部代理信息

 void

saveDelegation(java.lang.String delegated, java.lang.String delegate) 
          
保存一條代理信息

5.5   用戶詳細信息管理

5.5.1    UserDetailsManager

UserDetailsManager負責獲取用戶的信息(包括E-mail、暱稱、手機號等),主要用以發送催辦通知。UserDetailsManager接口包含的方法以下:

方法摘要

 UserDetailsEntity

findUserDetails(java.lang.String userId) 
          
根據用戶名獲取用戶詳細信息

5.5.2    UserDetailsEntity

UserDetailsEntity用以描述用戶詳細信息,注意它沒有強制要求提供諸如getName()這樣的方法,而是提供了一個getProperty(Stringname)方法:

方法摘要

<T> T

getProperty(java.lang.String name) 
          
獲取指定屬性的值

 java.lang.String[]

getPropertyNames() 
          
獲取全部的屬性名

 java.lang.String

getUserId() 
          
獲取用戶的ID

<T> void

setProperty(java.lang.String name, T value) 
          
設置指定屬性的值

UserDetailsEntity同時提供了幾個字符串常量:

字段摘要

static java.lang.String

STRING_PROPERTY_EMAIL 
          EMAIL
屬性名

static java.lang.String

STRING_PROPERTY_MOBILE_PHONE_NUMBER 
          
手機號碼屬性名

static java.lang.String

STRING_PROPERTY_NICK_NAME 
          
暱稱屬性名

static java.lang.String

STRING_PROPERTY_USER_ID 
          
用戶ID屬性名

5.5.3    UserDetailsManagerEx

UserDetailsManagerEx用以實現用戶信息的「寫」操做:

方法摘要

 void

removeAll() 
          
刪除全部用戶信息

 void

saveUserDetails(UserDetailsEntity userDetails) 
          
保存某個用戶的信息

 

5.6   用戶組成員關係管理

5.6.1    IdentityMembershipManager

IdentityMembershipManager負責獲取用戶組成員關係,簡單點,就是獲取指定用戶所在的組的ID列表,以及指定組內的成員ID列表。

方法摘要

java.util.List <java.lang.String>

findGroupIdsByUser(java.lang.String userId) 
          
獲取指定的用戶所在的組ID列表

 java.util.List <java.lang.String>

findUserIdsByGroup(java.lang.String groupId) 
          
獲取指定組的成員用戶ID列表

5.6.2    IdentityMembershipManagerEx

IdentityMembershipManagerEx提供了對成員關係信息的「寫」操做:

方法摘要

 void

removeAll() 
          
刪除全部成員關係

 void

saveMembership(java.lang.String userId, java.lang.String groupId) 
          
保存成員關係

6.    其餘幫助

本文檔的下載地址爲:https://gitee.com/bluejoe/openwebflow/tree/master/doc,可經過該地址及時查閱最新版本。

若是用戶須要查閱OpenWebFlow的Java API,能夠參考javadoc(https://gitee.com/bluejoe/openwebflow/tree/master/openwebflow-core/doc/javadoc)。

另外能夠關注Wiki(https://gitee.com/bluejoe/openwebflow/wiki),提交話題(https://gitee.com/bluejoe/openwebflow/issues),以及與做者bluejoe2008@gmail.com直接聯繫。

7.    Activiti的BUG及對策

目前做者發現Activiti框架存在2個bug,主要表如今:

第一個bug是在BaseBpmnJsonConverter將BPMN模型轉存爲JSON格式的時候,會忽略對true布爾值的輸出,這個bug會形成JsonConverterUtil.getPropertyValueAsBoolean()獲取到false值(由於此時的判斷標準變成Yes或No)。該bug的報告地址:https://github.com/Activiti/Activiti/pull/464#event-204722250

另一個bug是在BPMN文件加載的時候,當本地字符集爲非UTF-8(如:GB2312)時,會出現模型加載的錯誤。該bug的報告地址:https://github.com/Activiti/Activiti/pull/486#event-220121880

目前(2014年)做者已經針對以上兩個bug提交了bugfix並被master版本合併。不過考慮到版本穩定性問題,OpenWebFlow最新版本仍是採用了其餘方法來避免瞭如上bug的發生。

相關文章
相關標籤/搜索