Activiti工作流框架中任务流程元素详解!使用任务元素进行任务的调度和执行
任务
用户任务
描述
- 用户任务用来设置必须由人员完成的工作
- 当流程执行到用户任务,会创建一个新任务,并把这个新任务加入到分配人或群组的任务列表中
图形标记
- 用户任务显示成一个普通任务(圆角矩形),左上角有一个小用户图标
XML内容
- XML中的用户任务定义:id属性是必须的,name属性是可选的:
<userTask id="theTask" name="Important task" />
- 用户任务可以设置描述,添加documentation元素可以定义描述:
<userTask id="theTask" name="Schedule meeting" >
<documentation>
Schedule an engineering meeting for next week with the new hire.
</documentation>
- 描述文本可以通过标准的java方法来获取:
task.getDescription()
持续时间
- 任务可以用一个字段来描述任务的持续时间
- 可以使用查询API来对持续时间进行搜索,根据在时间之前或之后进行搜索
- Activiti提供了一个节点扩展,在任务定义中设置一个表达式,这样在任务创建时就可以设置初始持续时间
- 表达式应该是:
- java.util.Date
- java.util.String(ISO8601格式),ISO8601持续时间(比如PT50M)
- null
- 在流程中使用上述格式输入日期,或在前一个服务任务中计算一个时间.这里使用了持续时间,持续时间会基于当前时间进行计算,再通过给定的时间段累加: 使用"PT30M"作为持续时间,任务就会从现在开始持续30分钟
<userTask id="theTask" name="Important task" activiti:dueDate="${dateVariable}"/>
- 任务的持续时间也可以通过TaskService修改,或在TaskListener中通过传入的DelegateTask参数修改
用户分配
- 用户任务可以直接分配给一个用户,通过humanPerformer元素定义
- humanPerformer定义需要一个resourceAssignmentExpression来实际定义用户.目前只支持formalExpressions
<process ... >
...
<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元素类似**,需要指定表达式中的每个项目是人员还是群组**
<process ... >
...
<userTask id='theTask' name='important task' >
<potentialOwner>
<resourceAssignmentExpression>
<formalExpression>user(kermit), group(management)</formalExpression>
</resourceAssignmentExpression>
</potentialOwner>
</userTask>
- 使用potentialOwner元素定义的任务可以通过TaskService获取:
List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit");
这会获取所有kermit为候选人的任务,表达式中包含user(kermit).这也会获得所有分配包含kermit这个成员的群组(比如,group(management),前提是kermit是这个组的成员,并且使用了activiti的账号组件).用户所在的群组是在运行阶段获取的, 它们可以通过IdentityService进行管理
- 如果没有显式指定设置的是用户还是群组,引擎会默认当做群组处理
- 下面的设置与使用group(accountancy)一样:
<formalExpression>accountancy</formalExpression>
Activiti对任务分配的扩展
- 当分配不复杂时,用户和组的设置非常麻烦.为避免复杂性,可以使用用户任务的自定义扩展
- assignee属性: 直接把用户任务分配给指定用户(和使用humanPerformer 效果完全一样)
<userTask id="theTask" name="my task" activiti:assignee="kermit" />
- candidateUsers属性: 为任务设置候选人(和使用potentialOwner效果完全一样,不需要像使用potentialOwner通过user(kermit)声明,这个属性只能用于人员)
<userTask id="theTask" name="my task" activiti:candidateUsers="kermit, gonzo" />
- candidateGroups属性: 为任务设置候选组(和使用potentialOwner效果完全一样,不需要像使用potentialOwner通过group(management)声明,这个属性只能用于群组)
<userTask id="theTask" name="my task" activiti:candidateGroups="management, accountancy" />
- candidateUsers和candidateGroups可以同时设置在同一个用户任务中
- Activiti中虽然有账号管理组件和IdentityService ,账号组件不会检测设置的用户是否存在. Activiti允许与其他已存的账户管理方案集成
- 使用创建事件的任务监听器 来实现自定义的分配逻辑:
<userTask id="task1" name="My task" >
<extensionElements>
<activiti:taskListener event="create" class="org.activiti.MyAssignmentHandler" />
</extensionElements>
</userTask>
- DelegateTask会传递给TaskListener的实现,通过它可以设置执行人,候选人和候选组
public class MyAssignmentHandler implements TaskListener {
public void notify(DelegateTask delegateTask) {
// Execute custom identity lookups here
// and then for example call following methods:
delegateTask.setAssignee("kermit");
delegateTask.addCandidateUser("fozzie");
delegateTask.addCandidateGroup("management");
...
}
}
- 使用spring时,使用表达式把任务监听器设置为spring代理的bean,让这个监听器监听任务的创建事件
- 示例:执行者会通过调用ldapService这个spring bean的findManagerOfEmployee方法获得.流程变量emp会作为参数传递给bean
<userTask id="task" name="My Task" activiti:assignee="${ldapService.findManagerForEmployee(emp)}"/>
- 可以用来设置候选人和候选组:
<userTask id="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");
}
}
脚本任务
描述
- 脚本任务是一个自动节点
- 当流程到达脚本任务,会执行对应的脚本
图形标记
- 脚本任务显示为标准BPMN 2.0任务(圆角矩形),左上角有一个脚本小图标
XML内容
- 脚本任务定义需要指定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平台的脚本语言).默认Javascript会包含在JDK中,不需要额外的依赖.如果要使用其他的脚本引擎,必须要是JSR-223引擎兼容的.还需要把对应的jar添加到classpath下, 并使用合适的名称:activiti单元测试经常使用groovy
- groovy脚本引擎放在groovy-all.jar中,在2.0版本之前,脚本引擎是groovy jar的一部分.使用需要添加依赖:
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.x.x<version>
</dependency>
脚本变量
- 到达脚本任务的流程可以访问的所有流程变量,都可以在脚本中使用
<script>
sum = 0
for ( i in inputArray ) {
sum += i
}
</script>
- 也可以在脚本中设置流程变量,直接调用execution.setVariable(“variableName”, variableValue)
- 默认,不会自动保存变量(activiti 5.12之前)
- 可以在脚本中自动保存任何变量,只要把scriptTask的autoStoreVariables属性设置为true
- 最佳实践是不要使用,而是显式调用execution.setVariable()
<scriptTask id="script" scriptFormat="JavaScript" activiti:autoStoreVariables="false">
参数默认为false: 如果没有为脚本任务定义设置参数,所有声明的变量将只存在于脚本执行的阶段
- 在脚本中设置变量: 这些命名已经被占用,不能用作变量名- out, out:print, lang:import, context, elcontext.
<script>
def scriptVar = "test123"
execution.setVariable("myVar", scriptVar)
</script>
脚本结果
- 脚本任务的返回值可以通过制定流程变量的名称,分配给已存在或者一个新流程变量,需要使用脚本任务定义的’activiti:resultVariable’属性
- 任何已存在的流程变量都会被脚本执行的结果覆盖
- 如果没有指定返回的变量名,脚本的返回值会被忽略
<scriptTask id="theScriptTask" name="Execute script" scriptFormat="juel" activiti:resultVariable="myVar">
<script>#{echo}</script>
</scriptTask>
脚本的结果-表达式 #{echo} 的值会在脚本完成后,设置到myVar变量中
Java服务任务
描述
- Java服务任务用来调用外部Java类
图形标记
- Java服务任务显示为圆角矩形,左上角有一个齿轮小图标
XML内容
- 声明Java调用逻辑有四种方式:
- 实现JavaDelegate或者ActivityBehavior
- 执行解析代理对象的表达式
- 调用一个方法表达式
- 调用一个值表达式
- 执行一个在流程执行中调用的类,需要在activiti:class属性中设置全类名:
<serviceTask id="javaService"
name="My Java Service Task"
activiti:class="org.activiti.MyJavaDelegate" />
- 使用表达式调用一个对象,对象必须遵循一些规则,并使用activiti:delegateExpression属性进行创建:
<serviceTask id="serviceTask" activiti:delegateExpression="${delegateExpressionBean}" />
delegateExpressionBean是一个实现了JavaDelegate接口的bean,定义在实例的spring容器中
要执行指定的UEL方法表达式, 需要使用activiti:expression:
<serviceTask id="javaService"
name="My Java Service Task"
activiti:expression="#{printer.printMessage()}" />
方法printMessage()会调用名为printer对象的方法
- 为表达式中的方法传递参数:
<serviceTask id="javaService"
name="My Java Service Task"
activiti:expression="#{printer.printMessage(execution, myVar)}" />
调用名为printer对象上的方法printMessage.第一个参数是DelegateExecution, 在表达式环境中默认名称为execution. 第二个参数传递的是当前流程的名为myVar的变量
要执行指定的UEL方法表达式, 需要使用activiti:expression:
<serviceTask id="javaService"
name="My Java Service Task"
activiti:expression="#{split.ready}" />
ready属性的getter方法:getReady() 会作用于名为split的bean上.这个对象会被解析为流程对象和spring环境中的对象
实现
- 要在流程执行中实现一个调用的类,这个类需要实现org.activiti.engine.delegate.JavaDelegate接口,并在execute方法中提供对应的业务逻辑.当流程执行到特定阶段,会指定方法中定义好的业务逻辑,并按照默认BPMN 2.0中的方式离开节点
- 示例:
- 创建一个java类的例子,对流程变量中字符串转换为大写
- 这个类需要实现org.activiti.engine.delegate.JavaDelegate接口,要求实现execute(DelegateExecution) 方法,包含的业务逻辑会被引擎调用
- 流程实例信息:流程变量和其他信息,可以通过DelegateExecution接口访问和操作
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定义的class只会创建一个java类的实例
- 所有流程实例都会共享相同的类实例,并调用execute(DelegateExecution)
- 类不能使用任何成员变量,必须是线程安全的,必须能模拟在不同线程中执行.影响着属性注入的处理方式
- 流程定义中引用的类(activiti:class)不会在部署时实例化
- 只有当流程第一次执行到使用类的时候,类的实例才会被创建
- 如果找不到类,会抛出一个ActivitiException
- 这个原因是部署环境(更确切是的classpath)和真实环境往往是不同的:当使用ant或业务归档上传到Activiti Explorer来发布流程,classpath没有包含引用的类
- 内部实现类也可以提供实现org.activiti.engine.impl.pvm.delegate.ActivityBehavior接口的类
- 实现可以访问更强大的ActivityExecution,它可以影响流程的流向
- 注意: 这应该尽量避免.只有在高级情况下并且确切知道要做什么的情况下,再使用ActivityBehavior接口
属性注入
- 为代理类的属性注入数据. 支持如下类型的注入:
- 固定的字符串
- 表达式
- 如果有效的话,数值会通过代理类的setter方法注入,遵循java bean的命名规范(比如fistName属性对应setFirstName(Xxx)方法)
- 如果属性没有对应的setter方法,数值会直接注入到私有属性中
- 一些环境的SecurityManager不允许修改私有属性,要把想注入的属性暴露出对应的setter方法来
- 无论流程定义中的数据是什么类型,注入目标的属性类型都应该是 org.activiti.engine.delegate.Expression
- 示例:
- 把一个常量注入到属性中
- 属性注入可以使用class属性
- 在声明实际的属性注入之前,需要定义一个extensionElements的XML元素
<serviceTask id="javaService"
name="Java service invocation"
activiti:class="org.activiti.examples.bpmn.servicetask.ToUpperCaseFieldInjected">
<extensionElements>
<activiti:field name="text" stringValue="Hello World" />
</extensionElements>
</serviceTask>
ToUpperCaseFieldInjected类有一个text属性,类型是org.activiti.engine.delegate.Expression. 调用text.getValue(execution) 时,会返回定义的字符串Hello World
- 可以使用长文字(比如,内嵌的email),使用activiti:string子元素:
<serviceTask id="javaService"
name="Java service invocation"
activiti:class="org.activiti.examples.bpmn.servicetask.ToUpperCaseFieldInjected">
<extensionElements>
<activiti:field name="text">
<activiti:string>
Hello World
</activiti:string>
</activiti:field>
</extensionElements>
</serviceTask>
- 可以使用表达式,实现在运行期动态解析注入的值
- 这些表达式可以使用流程变量或spring定义的bean.
- 服务任务中的java类实例会在所有流程实例中共享:
- 为了动态注入属性的值,可以在org.activiti.engine.delegate.Expression中使用值和方法表达式
- 会使用传递给execute方法的DelegateExecution参数进行解析
<serviceTask id="javaService" name="Java service invocation"
activiti:class="org.activiti.examples.bpmn.servicetask.ReverseStringsFieldInjected">
<extensionElements>
<activiti:field name="text1">
<activiti:expression>${genderBean.getGenderString(gender)}</activiti:expression>
</activiti:field>
<activiti:field name="text2">
<activiti:expression>Hello ${gender == 'male' ? 'Mr.' : 'Mrs.'} ${name}</activiti:expression>
</activiti:field>
</ extensionElements>
</ serviceTask>
- 示例:
- 注入表达式,并使用在当前传入的DelegateExecution解析:
public class 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());
}
}
- 可以把表达式设置成一个属性,而不是子元素:
- 因为java类实例会被重用,注入只会发生一次,当服务任务调用第一次的时候发生注入
- 当代码中的属性改变了,值也不会重新注入,把它们看作是不变的,不用修改它们
服务任务结果
- 服务流程返回的结果(使用表达式的服务任务)可以分配给已经存在的或新的流程变量
- 通过指定服务任务定义的activiti:resultVariable属性来实现
- 指定的流程变量会被服务流程的返回结果覆盖
- 如果没有指定返回变量名,就会忽略返回结果
<serviceTask id="aMethodExpressionServiceTask"
activiti:expression="#{myService.doSomething()}"
activiti:resultVariable="myVar" />
服务流程的返回值(在myService上调用doSomething() 方法的返回值,myService可能是流程变量,也可能是spring的bean),在服务执行完成之后,会设置到名为myVar的流程变量里
处理异常
执行自定义逻辑时,常常需要捕获对应的业务异常,在流程内部进行处理
- 抛出BPMN Errors:
- 在服务任务或脚本任务的代码里抛出BPMN error:
- 要从JavaDelegate,脚本,表达式和代理表达式中抛出名为BpmnError的特殊ActivitiExeption
- 引擎会捕获这个异常,把它转发到对应的错误处理中:边界错误事件或错误事件子流程
- 在服务任务或脚本任务的代码里抛出BPMN error:
public class ThrowBpmnErrorDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) throws Exception {
try {
executeBusinessLogic();
} catch (BusinessException e) {
throw new BpmnError("BusinessExceptionOccured");
}
}
}
构造参数是错误代码,会被用来决定哪个错误处理器会来响应这个错误
这个机制只用于业务失败,应该被流程定义中设置的边界错误事件或错误事件子流程处理. 技术上的错误应该使用其他异常类型,通常不会在流程里处理
- 异常顺序流:
内部实现类在一些异常发生时,让流程进入其他路径
<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 class ThrowsExceptionBehavior implements ActivityBehavior {
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);
}
}
JavaDelegate使用Activiti服务
- 需要在Java服务任务中使用Activiti服务的场景: 比如,通过RuntimeService启动流程实例,而callActivity不满足需求
- org.activiti.engine.delegate.DelegateExecution允许通过 org.activiti.engine.EngineServices接口直接获得这些服务:
public class StartProcessInstanceTestDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) throws Exception {
RuntimeService runtimeService = execution.getEngineServices().getRuntimeService();
runtimeService.startProcessInstanceByKey("myProcess");
}
}
- 所有activiti服务的API都可以通过这个接口获得
- 使用这些API调用出现的所有数据改变,都是在当前事务中
- 在例如spring和CDI这样的依赖注入环境也会起作用,无论是否启用了JTA数据源
- 示例: 下面的代码功能与上面的代码一致,这是RuntimeService是通过依赖注入获得,而不是通过org.activiti.engine.EngineServices接口
@Component("startProcessInstanceDelegate")
public class StartProcessInstanceTestDelegateWithInjection {
@Autowired
private RuntimeService runtimeService;
public void startProcess() {
runtimeService.startProcessInstanceByKey("oneTaskProcess");
}
}
- 因为服务调用是在当前事务里,数据的产生或改变,在服务任务执行完之前,还没有提交到数据库.所以API对于数据库数据的操作,意味着未提交的操作在服务任务的API调用中都是不可见的
WebService任务
描述
- WebService任务可以用来同步调用一个外部的WebService
图形标记
- WebService任务与Java服务任务显示效果一样(圆角矩形,左上角有一个齿轮小图标)
XML内容
- 要使用WebService需要导入操作和类型,可以使用import标签来指定WebService的WSDL
<import importType="http://schemas.xmlsoap.org/wsdl/"
location="http://localhost:63081/counter?wsdl"
namespace="http://webservice.activiti.org/" />
声明告诉activiti导入WSDL定义,但没有创建itemDefinition和message
- 假设想调用一个名为prettyPrint的方法,必须创建为请求和响应信息对应的message和itemDefinition
<message id="prettyPrintCountRequestMessage" itemRef="tns:prettyPrintCountRequestItem" />
<message id="prettyPrintCountResponseMessage" itemRef="tns:prettyPrintCountResponseItem" />
<itemDefinition id="prettyPrintCountRequestItem" structureRef="counter:prettyPrintCount" />
<itemDefinition id="prettyPrintCountResponseItem" structureRef="counter:prettyPrintCountResponse" />
- 在申请服务任务之前,必须定义实际引用WebService的BPMN接口和操作
- 基本上,定义接口和必要的操作.对每个操作都会重用上面定义的信息作为输入和输出
- 示例:
- 定义了counter接口和prettyPrintCountOperation操作:
<interface name="Counter Interface" implementationRef="counter:Counter">
<operation id="prettyPrintCountOperation" name="prettyPrintCount Operation"
implementationRef="counter:prettyPrintCount">
<inMessageRef>tns:prettyPrintCountRequestMessage</inMessageRef>
<outMessageRef>tns:prettyPrintCountResponseMessage</outMessageRef>
</operation>
</interface>
然后定义WebService任务,使用WebService实现,并引用WebService操作
<serviceTask id="webService"
name="Web service invocation"
implementation="##WebService"
operationRef="tns:prettyPrintCountOperation">
WebService任务IO规范
- 每个WebService任务可以定义任务的输入输出IO规范
<ioSpecification>
<dataInput itemSubjectRef="tns:prettyPrintCountRequestItem" id="dataInputOfServiceTask" />
<dataOutput itemSubjectRef="tns:prettyPrintCountResponseItem" id="dataOutputOfServiceTask" />
<inputSet>
<dataInputRefs>dataInputOfServiceTask</dataInputRefs>
</inputSet>
<outputSet>
<dataOutputRefs>dataOutputOfServiceTask</dataOutputRefs>
</outputSet>
</ioSpecification>
WebService任务数据输入关联
- 指定数据输入关联有两种方式:
- 使用表达式
- 使用简化方式
- 使用表达式指定数据输入关联: 需要定义来源和目的item,并指定每个item属性之间的对应关系:
<dataInputAssociation>
<sourceRef>dataInputOfProcess</sourceRef>
<targetRef>dataInputOfServiceTask</targetRef>
<assignment>
<from>${dataInputOfProcess.prefix}</from>
<to>${dataInputOfServiceTask.prefix}</to>
</assignment>
<assignment>
<from>${dataInputOfProcess.suffix}</from>
<to>${dataInputOfServiceTask.suffix}</to>
</assignment>
</dataInputAssociation>
分配item的前缀和后缀
- 使用简化方式指定数据输入关联: sourceRef元素是activiti的变量名,targetRef元素是item定义的一个属性:
<dataInputAssociation>
<sourceRef>PrefixVariable</sourceRef>
<targetRef>prefix</targetRef>
</dataInputAssociation>
<dataInputAssociation>
<sourceRef>SuffixVariable</sourceRef>
<targetRef>suffix</targetRef>
</dataInputAssociation>
PrefixVariable变量的值分配给prefix属性,把SuffixVariable变量的值分配给suffix属性
WebService任务数据输出关联
- 指定数据输出关联有两种方式:
- 使用表达式
- 使用简化方式
- 使用表达式指定数据输出关联: 需要定义目的变量和来源表达式
<dataOutputAssociation>
<targetRef>dataOutputOfProcess</targetRef>
<transformation>${dataOutputOfServiceTask.prettyPrint}</transformation>
</dataOutputAssociation>
方法和数据输入关联完全一样
- 使用简化方式指定数据输出关联: sourceRef元素是item定义的一个属性,targetRef元素是activiti的变量名
<dataOutputAssociation>
<sourceRef>prettyPrint</sourceRef>
<targetRef>OutputVariable</targetRef>
</dataOutputAssociation>
方法和数据输入关联完全一样
业务规则任务
描述
- 业务规则任务用来同步执行一个或多个规则
- Activiti使用drools规则引擎执行业务规则:
- 包含业务规则的.drl文件必须和流程定义一起发布
- 流程定义里包含了执行这些规则的业务规则任务
- 流程使用的所有.drl文件都必须打包在流程BAR文件里
- 如果想要自定义规则任务的实现: 想用不同方式使用drools,或者使用完全不同的规则引擎.你可以使用BusinessRuleTask上的class或表达式属性
图形标记
- 业务规则任务是一个圆角矩形,左上角使用一个表格小图标进行显示
XML内容
- 要执行部署流程定义的BAR文件中的一个或多个业务规则,需要定义输入和输出变量:
- 对于输入变量定义,可以使用逗号分隔的一些流程变量
- 输出变量定义只包含一个变量名,会把执行业务规则后返回的对象保存到对应的流程变量中
- 注意: 结果变量会包含一个对象列表,如果没有指定输出变量名称,默认会使用 org.activiti.engine.rules.OUTPUT
<process id="simpleBusinessRuleProcess">
<startEvent id="theStart" />
<sequenceFlow sourceRef="theStart" targetRef="businessRuleTask" />
<businessRuleTask id="businessRuleTask" activiti:ruleVariablesInput="${order}"
activiti:resultVariable="rulesOutput" />
<sequenceFlow sourceRef="businessRuleTask" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
- 业务规则任务也可以配置成只执行部署的.drl文件中的一些规则.这时要设置逗号分隔的规则名,只会执行rule1和rule2:
<businessRuleTask id="businessRuleTask" activiti:ruleVariablesInput="${order}"
activiti:rules="rule1, rule2" />
- 定义哪些规则不用执行:除了rule1和rule2以外,所有部署到流程定义同一个BAR文件中的规则都会执行:
<businessRuleTask id="businessRuleTask" activiti:ruleVariablesInput="${order}"
activiti:rules="rule1, rule2" exclude="true" />
- 可以用一个选项修改BusinessRuleTask的实现:
<businessRuleTask id="businessRuleTask" activiti:class="${MyRuleServiceDelegate}" />
BusinessRuleTask的功能和ServiceTask一样,但是使用BusinessRuleTask的图标来表示 在这里要执行业务规则
邮件任务
- Activiti强化了业务流程,支持自动邮件任务:
- 可以发送邮件给一个或多个参与者,包括支持cc,bcc,HTML内容等等
- 邮件任务不是BPMN 2.0规范定义的官方任务,Activiti中邮件任务是用专门的服务任务实现的
邮件服务器配置
- Activiti引擎要通过支持SMTP功能的外部邮件服务器发送邮件
- 为了实际发送邮件,引擎穾知道如何访问邮件服务器.下面的配置可以设置到activiti.cfg.xml配置文件中:
属性 | 是否必须 | 描述 |
---|---|---|
mailServerHost | 否 | 邮件服务器的主机名(比如:mail.mycorp.com).默认为localhost |
mailServerPort | 是 如果没有使用默认端口 |
邮件服务器上的SMTP传输端口.默认为25 |
mailServerDefaultFrom | 否 | 如果用户没有指定发送邮件的邮件地址,默认设置的发送者的邮件地址。默认为activiti@activiti.org |
mailServerUsername | 如果服务器需要 | 一些邮件服务器需要认证才能发送邮件.默认不设置 |
mailServerPassword | 如果服务器需要 | 一些邮件服务器需要认证才能发送邮件.默认不设置 |
mailServerUseSSL | 如果服务器需要 | 一些邮件服务器需要ssl交互.默认为false |
mailServerUseTLS | 如果服务器需要 | 一些邮件服务器(比如gmail)需要支持TLS.默认为false |
定义一个邮件任务
- 邮件任务是一个专用的服务任务, 这个服务任务的type设置为mail
<serviceTask id="sendMail" activiti:type="mail">
- 邮件任务是通过属性注入进行配置的.所有这些属性都可以使用EL表达式,可以在流程执行中解析. 下面的属性都可以设置:
属性 | 是否必须 | 描述 |
---|---|---|
to | 是 | 邮件的接受者.可以使用逗号分隔多个接受者 |
from | 否 | 邮件发送者的地址.如果不提供,会使用默认配置的地址 |
subject | 否 | 邮件的主题 |
cc | 否 | 邮件抄送人.可以使用逗号分隔多个接收者 |
bcc | 否 | 邮件暗送人.可以使用逗号分隔多个接收者 |
charset | 否 | 可以修改邮件的字符集,对很多非英语语言是必须设置的 |
html | 否 | 作为邮件内容的HTML |
text | 否 | 邮件的内容.,在需要使用原始文字(非富文本)的邮件时使用.可以与html一起使用,对于不支持富文本的邮件客户端.客户端会降级到仅显示文本的方式 |
htmlVar | 否 | 使用对应的流程变量作为e-mail的内容.和html的不同之处是内容中包含的表达式会在mail任务发送之前被替换掉 |
textVar | 否 | 使用对应的流程变量作为e-mail的纯文本内容.和text的不同之处是内容中包含的表达式会在mail任务发送之前被替换掉 |
ignoreException | 否 | 处理邮件失败时,是否忽略异常,不抛出ActivitiException,默认为false |
exceptionVariableName | 否 | 当设置了ignoreException=true处理email时不抛出异常,可以指定一个变量名来存储失败信息 |
实例
- 邮件任务的使用示例:
<serviceTask id="sendMail" activiti:type="mail">
<extensionElements>
<activiti:field name="from" stringValue="order-shipping@thecompany.com" />
<activiti:field name="to" expression="${recipient}" />
<activiti:field name="subject" expression="Your order ${orderId} has been shipped" />
<activiti:field name="html">
<activiti:expression>
<![CDATA[
<html>
<body>
Hello ${male ? 'Mr.' : 'Mrs.' } ${recipientName},<br/><br/>
As of ${now}, your order has been <b>processed and shipped</b>.<br/><br/>
Kind regards,<br/>
TheCompany.
</body>
</html>
]]>
</activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>
Mule任务
- Mule任务可以向Mule发送消息,用来强化Activiti的集成能力
- Mule任务不是BPMN 2.0规范定义的官方任务,Activiti中Mule任务是用专门的服务任务实现的
定义Mule任务
- Mule任务是一个专用的服务任务, 服务任务的type设置为mule
<serviceTask id="sendMule" activiti:type="mule">
- Mule任务是通过属性注入进行配置的.属性使用EL表达式, 可以在流程执行中解析
属性 | 是否必须 | 描述 |
---|---|---|
endpointUrl | 是 | 需要调用的Mule终端 |
language | 是 | 要使用解析荷载表达式(payloadExpression)属性的语言 |
payloadExpression | 是 | 作为消息荷载的表达式 |
resultVariable | 否 | 将要保存调用结果的变量名称 |
实例
- Mule任务的使用示例:
<extensionElements>
<activiti:field name="endpointUrl">
<activiti:string>vm://in</activiti:string>
</activiti:field>
<activiti:field name="language">
<activiti:string>juel</activiti:string>
</activiti:field>
<activiti:field name="payloadExpression">
<activiti:string>"hi"</activiti:string>
</activiti:field>
<activiti:field name="resultVariable">
<activiti:string>theVariable</activiti:string>
</activiti:field>
</extensionElements>
- 点赞
- 收藏
- 关注作者
评论(0)