一、了解工作流
1、工作流(Workflow),就是“業務過程的部分或整體在計算機應用環境下的自動化”,它主要解決的是“使在多個參與者之間按照某種預定義的規則傳遞文檔、信息或任務的過程自動進行,從而實現某個預期的業務目標,或者促使此目標的實現。
2、工作流管理系統(Workflow Management System, WfMS)是一個軟件系統,它完成工作量的定義和管理,並按照在系統中預先定義好的工作流邏輯進行工作流實例的執行。工作流管理系統不是企業的業務系統,而是為企業的業務系統的運行提供了一個軟件的支撐環境。
3、常見的工作流框架有Activity、JBPM、OSWorkFlow、WorkFlow。本系列使用activiti5.13版本。
4、工作流框架底層需要有數據庫提供支持,activiti5.13版本,有23張表。JBPM4.4框架有18張表。JBPM底層使用hibernate操作數據庫。Activiti框架底層使用的mybatis操作數據庫。
二、Activiti介紹
Activiti5是由Alfresco軟件在2010年5月17日發布的業務流程管理(BPM)框架,它是覆蓋了業務流程管理、工作流、服務協作等領域的一個開源的、靈活的、易擴展的可執行流程語言框架。Activiti基於Apache許可的開源BPM平台,創始人Tom Baeyens是JBoss jBPM的項目架構師,它特色是提供了eclipse插件,開發人員可以通過插件直接繪畫出業務流程圖。

三、下載與目錄結構
官網:https://www.activiti.org/ ,沒啥用,打開了也沒啥東西。直接在GitHub上下載。
GitHub:https://github.com/Activiti/Activiti 這里下載的時activity-dev
目錄結構如下:

database :提供了建表語句。
docs:該目錄包含了三種文檔:javadocs、userguide、xsd。
- javadocs:API文檔,包名按照功能模塊划分,org.activiti.engine.*。
- userguide:用戶手冊,包含環境配置、10分鍾快速入門以及各個功能模塊的使用教程。
- xsd:包含BPMN2.0規范的XSD文件以及Activiti擴展的自定義標簽XSD。
libs:開發用的jar包和源碼包。
wars:提供了兩個例子程序。
安裝activiti流程設計器插件
1、eclipse中安裝如下:
1.1、獲得插件的安裝包

1.2、解壓安裝包,復制到eclipse中的dropins目錄中

1.3、重啟eclipse,勾選save選項

IDEA 安裝Activiti Designer插件---actiBPM
安裝成功后,創建數據庫:
初始化表結構
方式1、使用activiti框架提供的建表語句
在database目錄下找到相應數據庫的建表語句,執行即可。這里我用的是mysql(可以手動執行,也可用工具)

手動執行:



工具的話就不用說了吧
方式2、使用activiti框架的自動建表功能。activiti框架提供了和hibernate類似的自動建表功能。
創建一個java項目,導入jar包,不知道導哪些jar包,可以到war目錄解壓示例程序。把lib目錄中的jar包拷過來即可。當然數據庫驅動包時必不可少的。
1、 不使用配置文件(不建議)
@Test
public void test1(){
//1.創建一個流程引擎配置對象
ProcessEngineConfiguration configuration= ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();
//設置數據源
configuration.setJdbcDriver("com.mysql.jdbc.Driver");
configuration.setJdbcUrl("jdbc:mysql:///activiti_demo");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("123456");
//設置自動建表
configuration.setDatabaseSchema("true");
//創建一個流程引擎對象,在創建流程引擎對象時會自動建表
ProcessEngine engine= configuration.buildProcessEngine();
}
2、使用配置文件
配置文件可以到示例程序的class目錄拷貝 activiti-context.xml,修改里面的內容即可。
配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!--配置流程引擎配置對象-->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///activiti_demo"/>
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="123456" />
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</bean>
java代碼
//使用配置文件
@Test
public void test2(){
//1.創建一個流程引擎配置對象
String resource="activiti-context.xml";
String beanName="processEngineConfiguration";
ProcessEngineConfiguration configuration= ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(resource,beanName);
//創建一個流程引擎對象,在創建流程引擎對象時會自動建表
ProcessEngine engine= configuration.buildProcessEngine();
}
3、使用配置文件(使用默認配置),要求配置文件名稱必須為activiti-context.xml或者activiti.cfg.xml,配置的信息必須為
配置文件如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!--配置流程引擎配置對象-->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///activiti_demo"/>
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="123456" />
<property name="databaseSchemaUpdate" value="true"/>
</bean>
<!--配置工廠,用於創建流程引擎 id必須為processEngine-->
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
</bean>
java代碼
//使用默認配置文件
@Test
public void test3(){
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
}
了解25張表
Activiti的后台是有數據庫的支持,所有的表都以ACT_開頭。 第二部分是表示表的用途的兩個字母標識。 用途也和服務的API對應。
- ACT_RE_*: 'RE'表示repository。 這個前綴的表包含了流程定義和流程靜態資源 (圖片,規則,等等)。
- ACT_RU_*: 'RU'表示runtime。 這些運行時的表,包含流程實例,任務,變量,異步任務等運行中的數據。 Activiti只在流程實例執行過程中保存這些數據, 在流程結束時就會刪除這些記錄。 這樣運行時表可以一直很小速度很快。
- ACT_ID_*: 'ID'表示identity。 這些表包含身份信息,比如用戶,組等等。
- ACT_HI_*: 'HI'表示history。 這些表包含歷史數據,比如歷史流程實例, 變量,任務等等。
- ACT_GE_*: 通用數據, 用於不同場景下。

使用框架提供的API完成流程操作
可以在項目中加入log4j,將框架執行的sql輸出到控制台,log4j提供的日志級別:Fatal error warn info debug trace
部署流程定義
需要先畫好流程圖
/**
* 部署流程定義(操作數據表:act_re_deployment、act_re_procdef、act_ge_bytearray)
*/
@Test
public void test4() {
// 獲得一個部署構建器對象,用於加載流程定義文件(test1.bpmn,test.png)完成流程定義的部署
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
DeploymentBuilder builder= processEngine.getRepositoryService().createDeployment();
// 加載流程定義文件
builder.addClasspathResource("process/test1.bpmn");
builder.addClasspathResource("process/test1.png");
// 部署流程定義
Deployment deployment = builder.deploy();
System.out.println(deployment.getId());
}
查詢流程定義列表
@Test
public void test5() {
//流程定義查詢對象,用於查詢act_re_procdef表
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();
//添加查詢條件
query.processDefinitionKey("bxlc");
query.orderByDeploymentId().desc();
//分頁查詢
query.listPage(0, 10);
List<ProcessDefinition> list = query.list();
for (ProcessDefinition item : list) {
System.out.print(item.getId());
}
}
啟動流程實例
什么是流程實例?根據一個流程定義具體的一次執行過程就是一個流程實例,一個流程定義對應多個流程實例(一對多關系)
為了演示:在流程圖中指定辦理人是誰,現在是寫死的,表示只能張三能提交請假申請。后面會講解如何動態指定。

//根據流程定義的Id啟動一個流程實例(操作ACT_RU_EXECUTION、ACT_RU_TASK、ACT_HI_PROCINST、ACT_HI_ACTINST、ACT_HI_TASKINST、ACT_RU_IDENTITYLINK、ACT_HI_IDENTITYLINK表)
@Test
public void test6() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
String processDefinitionId="qjlc:1:104";
ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceById(processDefinitionId);
System.out.print(processInstance.getId());//201
}
查詢個人任務列表
@Test
public void test7() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskQuery query = processEngine.getTaskService().createTaskQuery();
query.taskAssignee("張三");
List<Task> list = query.list();
for (Task item : list) {
System.out.print(item.getId()+"==="+item.getName());//204===提交請假申請
}
}
辦理任務
//辦理任務(主要操作ACT_RU_EXECUTION、ACT_RU_TASK表)
@Test
public void test8() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
processEngine.getTaskService().complete("204");
}
辦理任務后,流程就走到了下一個節點,再次查詢張三個人任務列表就查不到了,此時用李四去查就可以了。
使用Activiti框架的API操作流程
/**
* 使用Activiti框架的API操作流程
*/
public class ActivitiAPITest {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
/**
* 部署流程定義 方式一:讀取單個的流程定義文件 方式二:讀取zip壓縮文件
*/
@Test
public void test1() {
DeploymentBuilder deploymentBuilder = processEngine.getRepositoryService().createDeployment();
// 方式一:讀取單個的流程定義文件
deploymentBuilder.addClasspathResource("test1.bpmn");
deploymentBuilder.addClasspathResource("test1.png");
Deployment deployment = deploymentBuilder.deploy();
// 方式二:讀取zip壓縮文件
/*ZipInputStream zipInputStream = new ZipInputStream(this.getClass().getClassLoader().getResourceAsStream("process.zip"));
deploymentBuilder.addZipInputStream(zipInputStream);
deploymentBuilder.name("請假流程部署");
Deployment deployment = deploymentBuilder.deploy();*/
}
/**
* 查詢部署列表
*/
@Test
public void test2() {
// 部署查詢對象,查詢表act_re_deployment
DeploymentQuery query = processEngine.getRepositoryService().createDeploymentQuery();
List<Deployment> list = query.list();
for (Deployment deployment : list) {
String id = deployment.getId();
System.out.println(id);
}
}
/**
* 查詢流程定義列表
*/
@Test
public void test3() {
// 流程定義查詢對象,查詢表act_re_procdef
ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();
List<ProcessDefinition> list = query.list();
for (ProcessDefinition pd : list) {
System.out.println(pd.getName() + "" + pd.getId());
}
}
/**
* 刪除部署信息
*/
@Test
public void test4() {
String deploymentId = "1001";
// processEngine.getRepositoryService().deleteDeployment(deploymentId);
processEngine.getRepositoryService().deleteDeployment(deploymentId,true);
}
/**
* 刪除流程定義(通過刪除部署信息達到刪除流程定義的目的)
*/
@Test
public void test5() {
String deploymentId = "1401";
// processEngine.getRepositoryService().deleteDeployment(deploymentId);
processEngine.getRepositoryService().deleteDeployment(deploymentId,
true);
}
/**
* 查詢一次部署對應的流程定義文件名稱和對應的輸入流(bpmn png)
*
* @throws Exception
*/
@Test
public void test6() throws Exception {
String deploymentId = "101";
List<String> names = processEngine.getRepositoryService()
.getDeploymentResourceNames(deploymentId);
for (String name : names) {
System.out.println(name);
InputStream in = processEngine.getRepositoryService()
.getResourceAsStream(deploymentId, name);
// 將文件保存到本地磁盤
/*
* OutputStream out = new FileOutputStream(new File("d:\\" + name));
* byte[] b = new byte[1024]; int len = 0; while((len =
* in.read(b))!=-1) { out.write(b, 0, len); } out.close();
*/
FileUtils.copyInputStreamToFile(in, new File("d:\\" + name));
in.close();
}
}
/**
* 獲得png文件的輸入流
*
* @throws Exception
*/
@Test
public void test7() throws Exception {
String processDefinitionId = "qjlc:9:1204";
InputStream pngInputStream = processEngine.getRepositoryService()
.getProcessDiagram(processDefinitionId);
FileUtils.copyInputStreamToFile(pngInputStream, new File("d:\\my.png"));
}
/**
* 啟動流程實例 方式一:根據流程定義的id啟動 方式二:根據流程定義的key啟動(自動選擇最新版本的流程定義啟動流程實例)
*/
@Test
public void test8() {
/*
* String processDefinitionId = "qjlc:9:1204"; ProcessInstance
* processInstance =
* processEngine.getRuntimeService().startProcessInstanceById
* (processDefinitionId ); System.out.println(processInstance.getId());
*/
String processDefinitionKey = "qjlc";
ProcessInstance processInstance = processEngine.getRuntimeService()
.startProcessInstanceByKey(processDefinitionKey);
System.out.println(processInstance.getId());
}
/**
* 查詢流程實例列表,查詢act_ru_execution表
*/
@Test
public void test9(){
//流程實例查詢對象,查詢act_ru_execution表
ProcessInstanceQuery query = processEngine.getRuntimeService().createProcessInstanceQuery();
query.processDefinitionKey("qjlc");
query.orderByProcessInstanceId().desc();
query.listPage(0, 2);
List<ProcessInstance> list = query.list();
for (ProcessInstance pi : list) {
System.out.println(pi.getId() + " " + pi.getActivityId());
}
}
/**
* 結束流程實例,操作的表act_ru_execution act_ru_task
*/
@Test
public void test10(){
String processInstanceId = "1601";
processEngine.getRuntimeService().deleteProcessInstance(processInstanceId , "我願意");
}
/**
* 查詢任務列表
*/
@Test
public void test11(){
//任務查詢對象,查詢act_ru_task表
TaskQuery query = processEngine.getTaskService().createTaskQuery();
String assignee = "李四";
query.taskAssignee(assignee);
query.orderByTaskCreateTime().desc();
List<Task> list = query.list();
for (Task task : list) {
System.out.println(task.getId());
}
}
/**
* 辦理任務
*/
@Test
public void test12(){
String taskId = "2902";
processEngine.getTaskService().complete(taskId);
}
/**
* 直接將流程向下執行一步
*/
@Test
public void test13(){
String executionId = "2701";//流程實例id
processEngine.getRuntimeService().signal(executionId);
}
/**
* 查詢最新版本的流程定義列表
*/
@Test
public void test14(){
ProcessDefinitionQuery query = processEngine.getRepositoryService().createProcessDefinitionQuery();
query.orderByProcessDefinitionVersion().asc();
List<ProcessDefinition> list = query.list();
Map<String, ProcessDefinition> map = new HashMap<String, ProcessDefinition>();
for (ProcessDefinition pd : list) {
map.put(pd.getKey(), pd);
}
ArrayList<ProcessDefinition> lastList = new ArrayList<>(map.values());
for (ProcessDefinition processDefinition : lastList) {
System.out.println(processDefinition.getName() + " "+ processDefinition.getVersion() );
}
}
}
Activiti框架提供的Service對象
- RepositoryService----操作靜態的資源(流程定義,bpmn、png)
- RuntimeService-----操作流程實例(啟動流程實例、查詢流程實例、結束流程實例)
- TaskService-----操作任務(查詢任務、辦理任務)
- HistoryService----操作歷史數據
Activiti框架提供的對象(和表有對應關系)
- Deployment-----act_re_deployment
- ProcessDefinition----act_re_procdef
- ProcessInstance-----act_ru_execution
- Task-----act_ru_task
使用網頁版流程設計器
1、將activiti-explorer.war復制到tomcat中
2、啟動tomcat,訪問http://lcoalhost:8080/activiti-explorer
3、使用kermit/kermit登錄
4、
5、
參考文檔:http://www.cnblogs.com/llzgzljl/archive/2013/10/07/3356108.html
學習資源:http://www.mossle.com/index.do




