好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Spring Boot中使用Activiti的方法教程(二)

前言

前面一节 我们已经了解了activiti的基础概念,包括流程定义的用语和它的api功能,已经如何入手activiti,在这一节我们将结合代码具体学习使用。小图是我们需要完成的请假流程图:

正如我们在图中看到的,这是一个非常简单的流程:员工提出休假请求,提供休假天数和开始日期。请求发送给经理。他们可以批准/拒绝该请求。

如果获得批准,则会定义一个服务任务servicetask来发送确认电子邮件。如果被拒绝,员工可以选择修改并重新发送请求,也可以不执行任何操作。

此流程的bpmn 2.0定义文件vacationrequest.bpmn20.xml将start事件定义为:

?

1

2

3

4

5

6

7

8

9

10

<startevent id= "startevent" name= "请假" activiti:initiator= "employeename" >

  <extensionelements>

   <activiti:formproperty id= "numberofdays" name= "number of days" type= "long"

         required= "true" />

   <activiti:formproperty id= "startdate" name= "vacation start date (mm-dd-yyyy)"

         type= "date" datepattern= "mm-dd-yyyy hh:mm" required= "true" />

   <activiti:formproperty id= "reason" name= "reason for leave" type= "string" />

   <modeler:editor-resource-id><![cdata[startevent1]]></modeler:editor-resource-id>

  </extensionelements>

</startevent>

分配给用户组[management]的第一个用户任务usertask将如下所示:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

<usertask id= "handle_vacation_request" name= "申请请假" >

  <documentation>${employeename} 请假 ${numberofdays} 天

   (motivation: ${reason}).

  </documentation>

  <extensionelements>

   <activiti:formproperty id= "vacationapproval"

         name= "你要批准这个请假要求吗?"

         type= "enum"

         required= "true" />

   <activiti:formproperty id= "comments" name= "经理的批示" type= "string" />

   <modeler:allow-send-email><![cdata[ true ]]></modeler:allow-send-email>

   <modeler:activiti-idm-initiator><![cdata[ true ]]></modeler:activiti-idm-initiator>

   <modeler:editor-resource-id>

    <![cdata[sid-b9aa8e66-2f11-45d0-a270-b052e1a9248e]]></modeler:editor-resource-id>

  </extensionelements>

  <potentialowner>

   <resourceassignmentexpression>

    <formalexpression>management</formalexpression>

   </resourceassignmentexpression>

  </potentialowner>

</usertask>

使用servicetask,我们需要定义要执行的代码段。我们将sendemailservicetask.java类作为这段代码执行者。

?

1

2

3

4

5

6

7

<servicetask id= "send-email-confirmation" name= "发送邮件确认"

     activiti: class = "com.example.activitiwithspring.servicetasks.sendemailservicetask.java" >

  <extensionelements>

   <modeler:editor-resource-id>

    <![cdata[sid-2c5e1831- 9101 -4f70-9aef-4ba72b704205]]></modeler:editor-resource-id>

  </extensionelements>

</servicetask>

sendemailservicetask的代码如下:实现javadelegate接口,实现其execute方法:

?

1

2

3

4

5

6

7

public class sendemailservicetask implements javadelegate {

 

  public void execute(delegateexecution execution) {

   //logic to sent email confirmation

  }

 

}

通过在[sequenceflow]中添加[conditionexpression]标记来决定发送邮件在什么条件下触发,也就是定义一个条件流:

?

1

2

3

4

5

6

7

8

9

10

<sequenceflow id= "flow3" name= "批准"

     sourceref= "sid-12a577ae-5227-4918-8de1-dc077d70967c"

     targetref= "send-email-confirmation" >

  <extensionelements>

   <modeler:editor-resource-id>

    <![cdata[sid-609beb69-e833-4d2f-bd14-fc8f7fd3e9c7]]></modeler:editor-resource-id>

  </extensionelements>

  <conditionexpression xsi:type= "tformalexpression" >

   <![cdata[${vacationapproved == 'true' }]]></conditionexpression>

</sequenceflow>

这里,vacationapproved是上面的usertask的formproperty。

部署流程

为了使我们的流程被activiti engine所知,我们需要部署该流程。我们可以使用repositoryservice以编程方式执行此操作。让我们编写一个junit测试来看看:

?

1

2

3

4

5

6

7

8

9

10

@test

public void givenbpmn_whendeployprocess_thendeployed() {

  processengine processengine = processengines.getdefaultprocessengine();

  repositoryservice repositoryservice = processengine.getrepositoryservice();

  repositoryservice.createdeployment()

   .addclasspathresource( "org/activiti/test/vacationrequest.bpmn20.xml" )

   .deploy();

  long count = repositoryservice.createprocessdefinitionquery().count();

  asserttrue(count >= 1 );

}

部署意味着引擎将解析bpmn流程定义文件并将其转换为可执行文件。此外,还会将记录添加到每个部署的repository表中。之后,我们可以查询repository服务从而获取已部署的进程:也就是processdefinitions。

启动流程实例processinstance

在将processdefinition部署到activiti engine之后,我们可以通过创建processinstances来执行该流程定义。如果说processdefinition绘制的是一幅蓝图,那么processinstance就是它的执行实现。

对于一个processdefinition,可以有多个processinstances。

可以通过runtimeservice访问与processinstances相关的所有详细信息。

在我们的示例中,在开始事件中,我们需要传递休假天数、开始日期和原因。我们将使用流程变量,并在创建processinstance时传递它们。

编写一个junit测试用例实现上面想法:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@test

public void givendeployedprocess_whenstartprocessinstance_thenrunning() {

  //deploy the process definition

  map<string, object> variables = new hashmap >();

  variables.put( "employeename" , "john" );

  variables.put( "numberofdays" , 4 );

  variables.put( "vacationmotivation" , "i need a break!" );

 

  runtimeservice runtimeservice = processengine.getruntimeservice();

  processinstance processinstance = runtimeservice

    .startprocessinstancebykey( "vacationrequest" , variables);

  long count=runtimeservice.createprocessinstancequery().count();

 

  assertequals( "1" , count.tostring());

}

某个流程定义的多个实例将因流程变量而异,也就是说,同一份流程定义,因为变量不同,导致流程实例也会不同。

有多种方法启动流程实例,在这里,我们正在使用该流程的key:vacationrequest启动流程,启动流程实例后,我们可以通过查询runtimeservice来获取有关它的信息。

完成任务

当我们的流程实例开始运行时,第一步执行的是用户任务usertask,分配任务给用户组[management]的用户。该用户可能有一个收件箱,其中包含要由他们完成的任务列表。现在,如果我们想继续执行流程,则需要用户完成此任务。对于activiti engine,它被称为[完成任务]。

我们可以查询taskservice,获取任务对象,然后完成它。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

@test

public void givenprocessinstance_whencompletetask_thengotnexttask() {

  // 部署流程并开始一个流程实例

  taskservice taskservice = processengine.gettaskservice();

  list<task> tasks = taskservice.createtaskquery()

    .taskcandidategroup( "management" ).list();

  task task = tasks.get( 0 );

 

  map<string, object> taskvariables = new hashmap<>();

  taskvariables.put( "vacationapproved" , "false" );

  taskvariables.put( "comments" , "we have a tight deadline!" );

  taskservice.complete(task.getid(), taskvariables);

 

  task currenttask = taskservice.createtaskquery()

    .taskname( "修改休假请求" ).singleresult();

  assertnotnull(currenttask);

}

请注意,taskservice的complete()方法也接受所需的流程变量。我们传递了经理的回复。

在此之后,流程引擎将继续下一步。在这里,下一步询问员工是否要重新发送休假请求。

因此,我们的processinstance正在等待此usertask,其名称为[修改休假请求]。 

暂停和激活流程

我们可以暂停processdefinition和processinstance。如果我们暂停一个流程定义processdefinition,则在它暂停挂起时我们就无法创建它的实例。我们可以使用repositoryservice来做到这一点:

?

1

2

3

4

5

6

@test (expected = activitiexception. class )

public void givendeployedprocess_whensuspend_thennoprocessinstance() {

  // deploy the process definition

  repositoryservice.suspendprocessdefinitionbykey( "vacationrequest" );

  runtimeservice.startprocessinstancebykey( "vacationrequest" );

}

要再次激活它,我们只需要调用其中一个repositoryservice.activateprocessdefinitionxxx方法。

同样,我们可以使用runtimeservice暂停processinstance 。

结论

在本文中,我们了解了如何将activiti与spring boot结合使用。我们创建了一个示例processenginecofiguration文件,它可以帮助我们创建processengine。processengine提供的服务帮助我们管理和跟踪processdefinitions,processinstances,usertasks等。

示例代码位于 github 上。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

原文链接:https://www.jdon.com/springboot/spring-activiti-2.html

查看更多关于Spring Boot中使用Activiti的方法教程(二)的详细内容...

  阅读:38次