activiti07- Task
任务
用户任务:
用户任务,用来对那些需要人参与完成的工作进行建模。当流程执行到这样的用户任务时,会在被分配到该任务的用户或用户组的任务列表中创建新的任务。
用户任务中可以包含描述。事实上,任何BPMN 2.0中的元素都可以有描述。描述是通过添加documentation元素来定义。
<userTaskid="theTask"name="Schedule meeting"> <documentation> Schedule an engineering meeting for next week with the new hire. </documentation>
描述文本可以以标准java 的方式从任务中获得:task.getDescription()
到期时间
每个任务都含有一个表明该任务到期时间的字段。Query API可以用来查询在某个时间点的前或后任务是否过期。
有个Activity的扩展,允许在任务定义中指定一个表达式来设置在创建任务时任务初始的超期时间。该表达式结果必须是
java.util.Date 或null。例如,你可以使用由流程中之前表单输入或在之前Service Task计算出来的日期。
<userTaskid="theTask"name="Important task"activiti:dueDate="${dateVariable}"/>
用户分配
用户任务可以直接分配给用户。这是通过定义humanPerformer子元素来完成的。
<userTask id='theTask' name='important task'> <humanPerformer> <resourceAssignmentExpression><formalExpression>kermit</formalExpression> </resourceAssignmentExpression> </humanPerformer> </userTask>
只能有一个用户作为执行者分配到任务上。在Activiti术语中,该用户称为代理人(译注,或称为责任人)。存在代理人的任务在其他人的任务列表中是不可见的,这些任务存在于所谓的代理人个人任务列表中。
直接分配给用户的任务可以通过TaskService来获取,
List<Task> tasks = taskService.createTaskQuery().taskAssignee("kermit").list(); 也可以把任务放进所谓的人员的候选任务列表中。这时,就要利用potentialOwner了。用法类似于humanPerformer。一定要注意需要对formal表达式中的每个元素进行定义以指名是用户还是用户组(流程引擎是猜测不到的)。
<userTask id='theTask'name='important task'> <potentialOwner> <resourceAssignmentExpression> <formalExpression>user(kermit), group(management)</formalExpression> </resourceAssignmentExpression> </potentialOwner> </userTask>
使用potential owner定义的任务可以按照如下方式获取(或类似于在有代理者任务中使用Ta skQuery):
List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit");
这将获得所有kermit作为候选用户的任务,也就是,formal表达式包含的user(kermit)。这也会获得所有分配给kermit所在组(例如,group(management),如果kermit是那个组的成员,并且使用了identity 组件)的任务。用户组是在运行时解析的,并且用户组可以通过IdentityService 管理。如果不给文本字符串指定是用户还是用户组,流程引擎默认认为是用户组
Activiti对于任务分配的扩展 用户和用户组的分配在那些分配并不复杂的情况下显然是很麻烦的。为了避免这种复杂性,用户任务上的自定义扩展就变得可能了。 assignee属性:这个自定义扩展允许将用户任务直接分配给用户。
<userTask id="theTask" name="my task" activiti:assignee="kermit"/> 这与上面使用humanPerformer效果是一样的。
candidateUsers属性:这个自定义扩展可以使用户成为任务的候选者。
<userTaskid="theTask"name="my task"activiti:candidateUsers="kermit, gonzo"/> 这与上面使用potentialOwner效果是一样的。注意不要求使用像在potential owner中使用的user(kermit)声明,因为该属性只用于用户。
candidateGroups属性:这个自定义扩展允许为任务定义一组候选者。
<userTask id="theTask"name="my task"activiti:candidateGroups="management, accountancy"/> 这与上面使用potentialOwner效果是一样的。注意不要求使用像在potential owner中使用的group(management)声明,因为该属性只用于组。
candidateUsers和candidateGroups可以定义在同一用户任务上。
使用Spring时可能会使用到上面章节中介绍的自定义分配属性,并利用带表达式的任务监听器监听create事件将处理委托给Spring的bean。下面的例子中,代理人是通过调用ldapServiceSpring bean中的方法findManagerOfEmployee来设置的。传递的emp参数,是个流程变量
<userTaskid="task"name="My Task"activiti:assignee="${ldapService.findManagerForEmployee(emp)}"/> 这对于候选用户和候选组的情况也是类似的: <userTaskid="task"name="My Task"activiti:candidateUsers="${ldapService.findAllSales()}"/> 注意只有当被调用的方法返回类型是String或Collection<String>(对于候选用户和候选组)才有效。
public class FakeLdapService { public String findManagerForEmployee(String employee) { return"Kermit The Frog"; } public List<String> findAllSales() { return Arrays.asList("kermit", "gonzo", "fozzie"); }}
脚本任务
脚本任务是自动的活动。当流程执行到脚本任务时,执行相应的脚本。
通过指定script和scriptFormat来定义脚本任务。
<scriptTask id="theScriptTask"name="Execute script"scriptFormat="groovy"> <script> sum = 0 for ( i in inputArray ) { sum += i } </script> </scriptTask>
scriptFormat属性的值必须是JSR-223(Java平台脚本,scripting for the Java plateform)所兼容的名称。默认Groovy jar随Activiti的分发文件被一起分发了。如果你想要使用其他(JSR-223兼容的)脚本引擎,只要将相应的jar 添加到类路径下,然后使用恰当的名称就行了。
脚本中的变量
所有那些进入脚本任务的执行路径能访问到的流程变量都可以在脚本中使用。该例子中,脚本变量’inputArray’实际上是个(整形数组类型的)流程变量。
<script> sum = 0 for ( i in inputArray ) { sum += i } </script>
也可以使用赋值语句在脚本中设置流程变量。在上面的例子中,在脚本任务执行完成后’sum’变量将作为流程变量存储起来。要避免这种行为,可以使用本地脚本变量。在Groovy中,需要使用关键字’def’:’def sum = 0’。那样,流程变量就不会被存储了。
另一种方法是使用当前的execution来设置变量,它是被称为’execution’的保留变量。 <script> def scriptVar = "test123" execution.setVariable("myVar", scriptVar) </script>
注意:以下名称被保留,不能用来做为变量的名称:out、out:print、lang:import、context、elcontext。
脚本的结果
通过给脚本任务定义的’activity:resultVariable’属性指定一个字符串来表示流程变量名,就可以将脚本任务的返回值分配给一个现有的或新的流程变量。流程变量现值会被脚本执行结果值所重写。不指定结果变量名时,会忽略脚本的结果值。
<scriptTask id="theScriptTask"name="Execute script"scriptFormat="juel"activiti:resultVariable="myVar"> <script>#{echo}</script> </scriptTask>
上面的例子中,在脚本执行完成后,脚本执行的结果(表达式’#{echo}’的结果值)被设置到名称为’myVar’的流程变量中。
Java服务任务
Java服务任务用来调用外部Java类。
有4种方式来声明如何调用Java的逻辑:
指定实现了JavaDelegate或ActivitiBehavior的类
计算结果为代理对象的表达式
调用方法表达式
计算值表达式
要指定在流程执行期间被调用的类,需要使用’activity:class’属性来提供完全限定的类名。 <serviceTask id="javaService" name="My Java Service Task" activiti:class="org.activiti.MyJavaDelegate"/>
也可以使用解析结果为对象的表达式。这个对象必须遵循与使用activiti:class属性创建对象时一样的规则(见下文)。 <serviceTask id="serviceTask" activiti:delegateExpression="${delegateExpressionBean}"/> 这里,delegateExpressionBean是一个定义在Spring容器中的实现了JavaDelegate接口的bean。
使用属性activiti:expression指定一个会被计算的UEL方法表达式。 <serviceTask id="javaService" name="My Java Service Task" activiti:expression="#{printer.printMessage()}"/> 会调用printer对象上的方法printMessage(不带参数)。
也可以向表达式的方法中传递参数。 <serviceTask id="javaService" name="My Java Service Task" activiti:expression="#{printer.printMessage(execution, myVar)}"/> 会调用printer对象上的方法printMessage。传递的第一个参数是DelegateException,其在表达式上下文默认以execution来使用。传递的第二个参数是当前execution中名为myVar变量的值。
使用属性activiti:expression来指定一个会被计算的UEL值表达式。 <serviceTask id="javaService" name="My Java Service Task" activiti:expression="#{split.ready}"/> 会调用名称为split的bean上属性ready的getter方法,getReady(不带参数)。命名对象是在流程执行中的流程变量和( 如果适用)Spring上下文中被解析的。
要实现一个可以在流程执行期间中调用的类,该类需要实现org.activiti.engine.delegate.JavaDelegate接口,在execute方法中提供必要的逻辑。当流程执行到此步,会执行定义在该方法中的逻辑,然后以BPMN 2.0的默认方式离开该活动。
public class ToUppercase implements JavaDelegate { public void execute(DelegateExecution execution) throws Exception { String var = (String) execution.getVariable("input"); var = var.toUpperCase(); execution.setVariable("input", var); } }
注意:只会创建定义在serviceTask上的java类的一个实例。所有流程实例共享同一个用于调用execute(DelegateExecution)的类实例。这意味着,该类中一定不要使用成员变量,并且必须是线程安全的,因为可能会在不同的线程中同时执行该方法。
流程定义中引用的类(即使用activiti:class)在部署时不会被实例化。只有当流程第一次执行到使用到该类的时候,才创建该类的实例。如果找不到该类,会抛出ActivitiException。这是由于部署的环境(特别是类路径)与实际运行的环境往往是不同的。比如,在使用ant或在Activiti Explorer中使用业务归档文件来部署流程时,类路径不包含参照的类。
[内部的:非公布的实现类] 可能会提供一个实现了org.activiti.engine.impl.pvm.delegate.ActivityBehavior接口的类。接下来实现类就能够访问更强大的ActivityExecution了,比如,它可以影响流程的控制流。但要注意这个不是一个很好的做法,应该尽量避免这样做。所以,对于高级的用例,如果你真正知道你要做什么,建议使用接口ActivityBehavior。
字段的注入
可以向代理类的字段注入值。支持以下注入形式:
固定字符串值
表达式
如果可以的话,是通过遵循Java Bean的命名规范的代理类中(例如,字段firstName的setter方法是setFirstName(…))的public setter方法将值注入的。如果字段不存在可用的setter方法,将设置代理类的private成员变量。在一些情况下,SecurityManagers是不允许修改private字段的,所以给你要进行注入的字段公布public setter方法会更加安全。不管流程定义中值声明成什么类型,注入目标类上的setter或private字段的类型必须是org.activiti.engine.delegate.Expression。
下面的代码片段展示了如何向字段中注入常量。使用’class’属性进行字段注入。注意,在实际的字段注入声明的前面,需要声明’extensionElements’ XML元素,这是BPMN 2.0 XML模式的要求。
<serviceTask id="javaService" name="Java service invocation" activiti:class="org.activiti.examples.bpmn.servicetask.ToUpperCaseFieldInjected"> <extensionElements> <activiti:fieldname="text"stringValue="Hello World"/> </extensionElements> </serviceTask>
类ToUpperCaseFieldInjected有一个类型为org.activiti.engine.delegate.Expressiontext的text字段。当调用text.getValue(execution)时,返回配置的’Hello world’字符串。
或者,对于长文本(例如,一行e-mail),可以使用子元素’activiti:string’:
<serviceTask id="javaService" name="Java service invocation" activiti:class="org.activiti.examples.bpmn.servicetask.ToUpperCaseFieldInjected"> <extensionElements> <activiti:fieldname="text"> <activiti:string> Hello World </activiti:string> </activiti:field> </extensionElements> </serviceTask>
要注入运行时动态解析的值,可以使用表达式。表达式中可以使用流程变量,或Spring定义的bean(如果使用了Spring)。如服务任务实现中所描述的,所有流程实例共享一个定义在服务任务中的Java类实例。要想达到字段上值的动态注入,可以将值表达式和方法表达式注入到org.activiti.engine.delegate.Expression,它会使用execute方法中传进来的DelegateExecution对org.activiti.engine.delegate.Expression进行运算/调用。
<serviceTask id="javaService"name="Java service invocation" activiti:class="org.activiti.examples.bpmn.servicetask.ReverseStringsFieldInjected"> <extensionElements> <activiti:fieldname="text1"> <activiti:expression>${genderBean.getGenderString(gender)}</activiti:expression> </activiti:field> <activiti:fieldname="text2"> <activiti:expression> Hello ${gender == 'male' ? 'Mr.' : 'Mrs.'} ${name} </activiti:expression> </activiti:field> </extensionElements> </serviceTask>
下面的示例类使用了被注入的表达式,并使用了当前DelegateExecution对这些表达式进行解析。完整代码以及测试可以在org.activiti.examples.bpmn.servicetask.JavaServiceTaskTest.testExpressionFieldInjection中找到。
publicclass ReverseStringsFieldInjected implements JavaDelegate { private Expression text1; private Expression text2; public void execute(DelegateExecution execution) { String value1 = (String) text1.getValue(execution); execution.setVariable("var1", new StringBuffer(value1).reverse().toString()); String value2 = (String) text2.getValue(execution); execution.setVariable("var2", new StringBuffer(value2).reverse().toString()); } }
或者,你也可以以属性的方式设置表达式,而不是使用子元素,这样可以使XML显得不那么冗长。
<activiti:fieldname="text1"expression="${genderBean.getGenderString(gender)}"/> <activiti:fieldname="text1"expression="Hello ${gender == 'male' ? 'Mr.' : 'Mrs.'} ${name}"/>
由于该java类的实例是可重用的,所以注入只在serviceTask第一次被调用时发生。一旦在代码中修改过了这些字段,其值不会再被重新注入了,因此你应该把它们看作是不可变的,并且对它们不要做任何的修改。
服务任务的结果
通过为服务任务定义的’activiti:resultVariable’属性指定一个字符串表示的流程变量名,可以将服务执行(服务任务仅使用了表达式)的返回值分配给一个现有的或一个新的流程变量。服务执行的返回值会重写流程变量的当前值。如果没有指定结果变量名,服务执行的结果值会被忽略。
<serviceTask id="aMethodExpressionServiceTask" activiti:expression="#{myService.doSomething()}" activiti:resultVariable="myVar"/>
上面示例中,服务执行完成后,服务执行的结果(调用流程变量或Spring bean中名为’myService’的对象上方法’doSomething()’的返回值)被设置到了叫’myVar’的流程变量。
处理异常
在执行自定义的逻辑时,常常需要捕获某种异常。一个常见的用例是一旦某条路径上发生异常,将流程导向另一条路径。下面的例子展示了这是如何做到的。
<serviceTask id="javaService" name="Java service invocation" activiti:class="org.activiti.ThrowsExceptionBehavior"> </serviceTask> <sequenceFlow id="no-exception"sourceRef="javaService"targetRef="theEnd"/> <sequenceFlow id="exception"sourceRef="javaService"targetRef="fixException"/>
这里,服务任务有两条输出流,分别是exception和no-exception。一旦发生异常,顺序流的id 属性用来引导顺序流。
public void execute(ActivityExecution execution) throws Exception { String var = (String) execution.getVariable("var"); PvmTransition transition = null; try { executeLogic(var); transition = execution.getActivity().findOutgoingTransition("no-exception"); } catch (Exception e) { transition = execution.getActivity().findOutgoingTransition("exception"); } execution.take(transition); }
activiti07- Task的更多相关文章
- Concepts:Request 和 Task
当SQL Server Engine 接收到Session发出的Request时,SQL Server OS将Request和Task绑定,并为Task分配一个Workder.在TSQL Query执 ...
- .Net多线程编程—任务Task
1 System.Threading.Tasks.Task简介 一个Task表示一个异步操作,Task的创建和执行是独立的. 只读属性: 返回值 名称 说明 object AsyncState 表示在 ...
- nginx+iis+redis+Task.MainForm构建分布式架构 之 (redis存储分布式共享的session及共享session运作流程)
本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,上一篇分享文章制作是在windows上使用的nginx,一般正式发布的时候是在linux来配 ...
- windows+nginx+iis+redis+Task.MainForm构建分布式架构 之 (nginx+iis构建服务集群)
本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,由标题就能看出此内容不是一篇分享文章能说完的,所以我打算分几篇分享文章来讲解,一步一步实现分 ...
- Openstack Periodic Task
Openstack Periodic Task 周期性任务在各个模块的manager.py(computer,scheduler,cell,network)中添加. 添加方法:在模块manager类实 ...
- MapReduce剖析笔记之三:Job的Map/Reduce Task初始化
上一节分析了Job由JobClient提交到JobTracker的流程,利用RPC机制,JobTracker接收到Job ID和Job所在HDFS的目录,够早了JobInProgress对象,丢入队列 ...
- [Java定时器]用Spring Task实现一个简单的定时器.
今天做一个项目的的时候需要用到定时器功能.具体需求是: 每个月一号触发一次某个类中的方法去拉取别人的接口获取上一个月份车险过期的用户.如若转载请附上原文链接:http://www.cnblogs.co ...
- 定时管理器框架-Task.MainForm
入住博客园4年多了,一直都是看别人的博客,学习别人的知识,为各个默默无私贡献自己技术总结的朋友们顶一个:这几天突然觉得是时候加入该队列中,贡献出自己微弱的力量,努力做到每个月有不同学习总结,知识学习的 ...
- Task三个列子的分享
这次要分享的是C#Task任务的几个列子,感觉最实用的是封装的分页任务执行方法,这个方法步奏也是目前在我工作中执行多任务常用的,不知道各位也有这用的情况,那么开始吧. 1.顺序任务执行 //顺序任务执 ...
- webapi+Task并行请求不同接口实例
标题的名称定义不知道是否准确,不过我想表达的意思就是使用Task特性来同时请求多个不同的接口,然后合并数据:我想这种场景的开发对于对接过其他公司接口的人不会陌生,本人也是列属于之内,更多的是使用最原始 ...
随机推荐
- 内存数据库之Apache Ingite
上一篇文章,我们做了内存数据库的技术选型: 内存数据库技术选型 本文中,我们继续深入研究Apache Ignite,同时分享一些我们.Net的编码实践. 首先,Apache Ignite是一个内存数据 ...
- C#多线程爬虫抓取免费代理IP
这里用到一个HTML解析辅助类:HtmlAgilityPack,如果没有网上找一个增加到库里,这个插件有很多版本,如果你开发环境是使用VS2005就2.0的类库,VS2010就使用4.0,以此类推.. ...
- JVM命令工具开发
1.查看tomcat7_8080的gc状态 $ jps -v | awk '/tomcat7_8080/{print $1}' | xargs jstat -gcutil 2.查看tomcat7_80 ...
- 【Mybatis】 JdbcType 与 JavaType对应关系
一.MyBatis 通过包含的jdbcType类型 BIT FLOAT CHAR TIMESTAMP OTHER UNDEFINED TINYINT REAL VARCHAR BINARY BLOB ...
- 关于Yii2的checkboxList的初始选项设置问题
先在网上找了个checkboxList的描述: public static function checkboxList($name, $selection = null, $items = [], $ ...
- javascript页面间传递参数
1.通过URL传递参数 传递参数页 function setCity() { var str = document.getElementById("cityName"); if ( ...
- C#输出杨辉三角形
话不多说直接上代码: class Program { static void Main(string[] args) { ;//杨辉三角形的长度 Console.Write("输入杨辉三角长 ...
- 八大排序算法---基于python
本文节选自:http://python.jobbole.com/82270/ 本文用Python实现了插入排序.希尔排序.冒泡排序.快速排序.直接选择排序.堆排序.归并排序.基数排序. 1.插入排序 ...
- Android学习记录:SQLite数据库、res中raw的文件调用
SQLite数据库是一种轻量级的关系型数据库. 在android中保存数据或调用数据库可以利用SQLite. android中提供了几个类来管理SQLite数据库 SQLiteDatabass类用来对 ...
- tomcat配置单项HTTPS协议
1.进入到jdk下的bin目录 1)进入cmd窗口,cd进入目录: 2)找到JDK安装bin目录,shift+右击打开命令窗口: 3)如果配置类环境变量,在任意cmd命令窗口都可以: 2.输入 ...