Activiti工作流简单入门

自jBPM创始人Tom离开之后,jBPM和Activiti就开始大相径庭,jBPM被迫使用新的LGPL协议,而Activiti则使用一种更为宽松的Apache
License 2.0协议。不管使用jBPM还是Activiti,两者都遵循BPMN 2.0规范,都可满足项目的一般需求,相比于jBPM,Activiti使用起来不会进行太大的二次改动,但jBPM则是使用Drools较为强大的规则引擎作为后盾,至于两者谁优谁劣,需要在实际项目中权衡利弊。

BPMN 2.0

BPMN最初由业务流程倡议组织(BPMI)定案,现在BPMI并入到OMG(Object Management Group)了,则由OMG建立规范和维护。

BPMN 2.0正式更名为(Business Process Model And Notation)业务流程符号和模型,也有人继续称呼为业务流程建模标记法(Business Process Modeling Notaion),不过无所谓,不管是jBPM、Activiti还是国人开发的FixFlow,都遵循BPMN规范。

Maven配置

JBoss的开源框架都是比较庞大的,不过相对Activiti体积要小一点。下面为配置的依赖项。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

<!--Junit-->

<dependency>

    <groupId>junit</groupId>

    <artifactId>junit</artifactId>

    <version>${junit.version}</version>

</dependency>

 

<!--activiti-->

<dependency>

    <groupId>org.activiti</groupId>

    <artifactId>activiti-engine</artifactId>

    <version>${activiti.version}</version>

</dependency>

 

<dependency>

    <groupId>org.activiti</groupId>

    <artifactId>activiti-bpmn-layout</artifactId>

    <version>${activiti.version}</version>

</dependency>

 

<dependency>

    <groupId>org.activiti</groupId>

    <artifactId>activiti-spring</artifactId>

    <version>${activiti.version}</version>

</dependency>

 

<!--apache组件-->

...

整合数据库

为什么要整合数据库?如果不整合数据库,我们大可以使用Quartz这些框架来做流程任务。实际上,Work Flow是用于一种长周期的、几乎异步的项目运行环境中,并且我们时刻需要将工作流程的状态记录下来,就是一种既注重结果,又注重过程的事务中,因此,整合数据库很有必要。

下面为配置源数据的XML文件,并且将databaseSchemaUpdate属性配置为drop-create,即在运行前删除原有的数据内容。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<?xml

version
="1.0"

encoding
="UTF-8"?>

<beans

xmlns
="http://www.springframework.org/schema/beans"

       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">

 

    <bean

id
="processEngineConfiguration"

class
="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

        <property

name
="databaseSchemaUpdate"

value
="drop-create"/>

        <property

name
="jdbcUrl"

value
="jdbc:mysql://localhost:3306/db_activiti?useUnicode=true&amp;characterEncoding=utf-8"/>

        <property

name
="jdbcDriver"

value
="com.mysql.jdbc.Driver"/>

        <property

name
="jdbcUsername"

value
="root"/>

        <property

name
="jdbcPassword"

value
="****"/>

        <property

name
="jobExecutorActivate"

value
="true"/>

    </bean>

</beans>

默认配置文件名为activiti.cfg.xml,可以在源文件中找到。

另外,如果有必要,请将MySQL设置为区分大小写,即lower_case_table_names = 0。

数据内容会在运行前自动创建,详细表结构内容可参考官网完整信息。

创建工作流文件

由于BPMN规范的作用,一些高级的IDE会自动识别后缀为*.bpmn的文件,不过这些都无所谓,bpmn文件实际上就是XML文件,只是加上了一些图形的标记,如width、height、x和y的坐标,下面为一个招聘面试流程,只包含流程节点,不包含位置标记节点。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<?xml

version
="1.0"

encoding
="UTF-8"?>

<definitions

xmlns
="http://www.omg.org/spec/BPMN/20100524/MODEL"

             xmlns:activiti="http://activiti.org/bpmn"

             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

             targetNamespace="Examples"

             xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL

             http://www.omg.org/spec/BPMN/2.0/20100501/BPMN20.xsd">

    <process

id
="Interview"

name
="某公司2012年实习生招聘流程">

        <documentation>招聘工作流程</documentation>

        <startEvent

id
="start"

name
="实习生招聘启动"/>

        <userTask

id
="bishi"

name
="笔试"

activiti:candidateGroups
="人力资源部"/>

        <sequenceFlow

id
="flow1"

name
=""

sourceRef
="start"

targetRef
="bishi"/>

        <userTask

id
="yimian"

name
="技术一面"

activiti:candidateGroups
="技术部"/>

        <sequenceFlow

id
="flow2"

name
=""

sourceRef
="bishi"

targetRef
="yimian"/>

        <userTask

id
="ermian"

name
="技术二面"

activiti:candidateGroups
="技术部"/>

        <sequenceFlow

id
="flow3"

name
=""

sourceRef
="yimian"

targetRef
="ermian"/>

        <userTask

id
="hrmian"

name
="HR面"

activiti:candidateGroups
="人力资源部"/>

        <sequenceFlow

id
="flow4"

name
=""

sourceRef
="ermian"

targetRef
="hrmian"/>

        <userTask

id
="luyong"

name
="录用,发放Offer"

activiti:candidateGroups
="人力资源部"/>

        <sequenceFlow

id
="flow5"

name
=""

sourceRef
="hrmian"

targetRef
="luyong"/>

        <endEvent

id
="end"

name
="实习生招聘结束"/>

        <sequenceFlow

id
="flow6"

name
=""

sourceRef
="luyong"

targetRef
="end"/>

    </process>

 

</definitions>

为了便于阅读,一些高级IDE可以转化为图形符号,如下图:

测试运行

有了流程引擎的配置文件和流程文件后,就可以编写代码启动流程引擎并加载该流程文件了。测试清单如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

@Test

public

void

processTests(){

    //
加载配置文件

    ProcessEngine
processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(
"activiti.cfg.xml").buildProcessEngine();

    RepositoryService
repositoryService = processEngine.getRepositoryService();

    RuntimeService
runtimeService = processEngine.getRuntimeService();

    repositoryService.createDeployment().addClasspathResource("Interview.bpmn").deploy();

    String
processId = runtimeService.startProcessInstanceByKey(
"Interview").getId();

 

    TaskService
taskService = processEngine.getTaskService();

    //得到笔试的流程

    System.out.println("\n***************笔试流程开始***************");

 

    List<Task>
tasks = taskService.createTaskQuery().taskCandidateGroup(
"人力资源部").list();

    for

(Task task : tasks) {

        System.out.println("人力资源部的任务:name:"+task.getName()+",id:"+task.getId());

        taskService.claim(task.getId(),
"张三");

    }

 

    System.out.println("张三的任务数量:"+taskService.createTaskQuery().taskAssignee("张三").count());

    tasks
= taskService.createTaskQuery().taskAssignee(
"张三").list();

    for

(Task task : tasks) {

        System.out.println("张三的任务:name:"+task.getName()+",id:"+task.getId());

        taskService.complete(task.getId());

    }

 

    System.out.println("张三的任务数量:"+taskService.createTaskQuery().taskAssignee("张三").count());

    System.out.println("***************笔试流程结束***************");

 

    System.out.println("\n***************一面流程开始***************");

    tasks
= taskService.createTaskQuery().taskCandidateGroup(
"技术部").list();

    for

(Task task : tasks) {

        System.out.println("技术部的任务:name:"+task.getName()+",id:"+task.getId());

        taskService.claim(task.getId(),
"李四");

    }

 

    System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());

    for

(Task task : tasks) {

        System.out.println("李四的任务:name:"+task.getName()+",id:"+task.getId());

        taskService.complete(task.getId());

    }

 

    System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());

    System.out.println("***************一面流程结束***************");

 

    System.out.println("\n***************二面流程开始***************");

    tasks
= taskService.createTaskQuery().taskCandidateGroup(
"技术部").list();

    for

(Task task : tasks) {

        System.out.println("技术部的任务:name:"+task.getName()+",id:"+task.getId());

        taskService.claim(task.getId(),
"李四");

    }

 

    System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());

    for

(Task task : tasks) {

        System.out.println("李四的任务:name:"+task.getName()+",id:"+task.getId());

        taskService.complete(task.getId());

    }

 

    System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());

    System.out.println("***************二面流程结束***************");

 

    System.out.println("***************HR面流程开始***************");

    tasks
= taskService.createTaskQuery().taskCandidateGroup(
"人力资源部").list();

    for

(Task task : tasks) {

        System.out.println("技术部的任务:name:"+task.getName()+",id:"+task.getId());

        taskService.claim(task.getId(),
"李四");

    }

 

    System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());

    for

(Task task : tasks) {

        System.out.println("李四的任务:name:"+task.getName()+",id:"+task.getId());

        taskService.complete(task.getId());

    }

 

    System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());

    System.out.println("***************HR面流程结束***************");

 

    System.out.println("\n***************录用流程开始***************");

    tasks
= taskService.createTaskQuery().taskCandidateGroup(
"人力资源部").list();

    for

(Task task : tasks) {

        System.out.println("技术部的任务:name:"+task.getName()+",id:"+task.getId());

        taskService.claim(task.getId(),
"李四");

    }

 

    System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());

    for

(Task task : tasks) {

        System.out.println("李四的任务:name:"+task.getName()+",id:"+task.getId());

        taskService.complete(task.getId());

    }

 

    System.out.println("李四的任务数量:"+taskService.createTaskQuery().taskAssignee("李四").count());

    System.out.println("***************录用流程结束***************");

 

    HistoryService
historyService = processEngine.getHistoryService();

    HistoricProcessInstance
historicProcessInstance = historyService

            .createHistoricProcessInstanceQuery()

            .processInstanceId(processId).singleResult();

    System.out.println("\n流程结束时间:"+historicProcessInstance.getEndTime());

}

代码清单中使用 ProcessEngines类加载默认的流程配置文件(activiti.cfg.xml),再获取各个服务组件的实例。 RepositoryService主要用于管理流程的资源, RuntimeService主要用于流程运行时的流程管理,TaskService主要用于管理流程任务。最后, HistoricProcessInstance会将工作的流程历史记录下来。

时间: 2024-08-26 09:51:17

Activiti工作流简单入门的相关文章

Activiti工作流引擎使用

Activiti 工作流引擎使用 1.简单介工作流引擎与Activiti 对于工作流引擎的解释请参考百度百科:工作流引擎 1.1 我与工作流引擎 在第一家公司工作的时候主要任务就是开发OA系统,当然基本都是有工作流的支持,不过当时使用的工作流引擎是公司一些牛人开发的(据说是用一个开源的引擎修改的),名称叫CoreFlow:功能相对Activiti来说比较弱,但是能满足日常的使用,当然也有不少的问题所以后来我们只能修改引擎的代码打补丁. 现在是我工作的第二家公司,因为要开发ERP.OA等系统需要使

Windows系统下Node.js的简单入门教程

  这篇文章主要介绍了Windows系统下Node.js的简单入门教程,Node.js是用于后端编程的JavaScript框架,需要的朋友可以参考下 随着近日Paypal和Netflix宣告 迁移到Node.js, 服务器端Javascript平台已经证明其自身在企业领域的价值. 这对于Node来说是一小步,对于Javascript而言却是一大跨越啊! 来自.NET, Java, PHP, Ruby on Rails和更多技术领域的程序员, 所有游走于服务器端的编码者都会聚集到这个平台上. 作为

Ruby中的Socket编程简单入门

  这篇文章主要介绍了Ruby中的Socket编程简单入门,是Ruby网络编程学习中的基础知识,需要的朋友可以参考下 Ruby提供了两个访问级别的网络服务.在一个较低的水平,可以访问底层的操作系统,它可以实现面向连接和无连接协议的客户端和服务器支持基本的socket. Ruby也具有程序库,提供更高级别的访问特定的应用程序级的网络协议,如FTP,HTTP等. 这篇教程介绍 Ruby Socket编程概念及讲解一个简单的实例. 什么是Sockets? 套接字是一个双向通信信道的端点.socket能

rxjs简单入门

rxjs简单入门 rxjs全名Reactive Extensions for JavaScript,Javascript的响应式扩展, 响应式的思路是把随时间不断变化的数据.状态.事件等等转成可被观察的序列(Observable Sequence),然后订阅序列中那些Observable对象的变化,一旦变化,就会执行事先安排好的各种转换和操作 rxjs适用于异步场景,即前端交互中接口请求.浏览器事件以及自定义事件.通过使用rxjs带给我们前所未有的开发体验. 统一异步编程的规范,不管是Promi

【java开发系列】—— struts2简单入门示例

原文:[java开发系列]-- struts2简单入门示例 上篇推荐:JDK安装 前言 最近正好有时间总结一下,过去的知识历程,虽说东西都是入门级的,高手肯定是不屑一顾了,但是对于初次涉猎的小白们,还是可以提供点参考的. struts2其实就是为我们封装了servlet,简化了jsp跳转的复杂操作,并且提供了易于编写的标签,可以快速开发view层的代码. 过去,我们用jsp和servlet搭配,实现展现时,答题的过程是: 1 jsp出发action 2 servlet接受action,交给后台c

请问JSF框架可以使用Activiti工作流吗?

问题描述 请问JSF框架可以使用Activiti工作流吗? 快来个好心人吧,我已经焦头烂额了,请问,JSF框架可以使用Activiti工作流吗? 解决方案 activiti工作流框架 数据库设计说明书 解决方案二: JSF是MVC框架标准,而Activiti是一个流程框架,它们之间不矛盾,都可以用.我以前的项目就用过.

it-一个非计算机专业女生,培训什么会比较简单入门IT行业

问题描述 一个非计算机专业女生,培训什么会比较简单入门IT行业 一个外语系的学生想培训,学点什么,但不知道学什么好,最好是培训IT方面的,如UI等 请给出您宝贵的意见引导我们迷茫的普通二本学校,感激不尽! 解决方案 自己喜欢IT这一方面吗?学Java 比较上手,到时候转前台的设计也比较容易.java 之后的话 HTML5,CSS之内的都行.你可以去www.imooc.com 去看看,这是IT知识的慕课网.加油吧. 解决方案二: java现在都很热门,你是想从事什么专业的计算机专业?至于说什么培训

跪求Activiti工作流的资料

问题描述 跪求Activiti工作流的资料!!好心人求出现.现在网上资料少且难找,请问大家有没有好的视频和资料分享给小弟!或者好的书推荐也行!先谢谢大家了! 解决方案 解决方案二:自己顶自己!解决方案三: 解决方案四:Activiti工作流的少.jbpm估计多一点.解决方案五:csdn里面搜索

java 整合 activiti工作流 web流程设计器 整合视频教程 SSM

本视频为activiti工作流的web流程设计器整合视频教程 整合Acitiviti在线流程设计器(Activiti-Modeler 5.21.0 官方流程设计器) 本视频共讲了两种整合方式 1. 流程设计器和其它工作流项目分开部署的方式 2. 流程设计器和SSM框架项目整合在一起的方式 视频大小 1.13 GB ~[获取地址] QQ313596790 本视频均为本人亲自录的,另免费附加赠送Activiti工作流视频(企业开发实例讲解) (这个赠送的Activiti工作流视频里面的流程设计器用的