目录
Activiti流程任务
4、服务任务
服务任务用于请求流程外部服务或者自动执行程序,Activiti为服务任务提供了三种实现:Java Service Task、Web Service Task和Shell Task,其中Java Service Task允许直接提供Java类,当流程到达该任务时,执行相应的Java类,当流程到达Web Service Task时,会自动调用预先定义好的Web Service,Shell Task则会执行Shell命令。
BPMN2.0中只提供了serviceTask来表示服务任务,因此Activiti的这三种Task,均使用serviceTask进行配置。另外,除了这三种任务可以使用serviceTask来配置外,Email Task同样可以使用serviceTask,但是这两种Task也支持使用sendTask。
4.1、Java 服务任务
Activiti中提供了Java Service Task用于执行Java程序,图所示为Java Service Task的流程图。
使用Service Task执行Java程序有以下4种途径。
- 使用activiti:class属性指定一个Java类,但是该Java类必须是JavaDelegate或者ActivityBehavior的实现类。
- 使用activiti:delegateExpression属性并配合UEL表达式指定一个流程参数的实例,该实例的Java类同样需要是JavaDelegate或者ActivityBehavior的实现类,并且需要实现序列化接口。
- 使用activiti::expression属性配合JUEL表达式指定一个流程参数,该参数是一个对象的实例,并且需要指定使用的方法。
- 使用activiti::expression属性配合JUEL表达式指定一个流程参数,该参数是一个对象的实例,需要指定使用的对象的属性,该对象需要为这个使用的属性提供getter方法。
注意,如果在配置activiti:class属性时,使用了实现ActivityBehavior接口的方式,那么有可能会对流程的走向产生影响,因此Activiti的官方文档并不推荐使用该方式来指定Java类,并且在Activiti开放的API中也找不到该接口,因此本章不会涉及该部分内容。
4.2、实现JavaDelegate
为serviceTask提供activiti:class属性可以指定执行的Java类,配置时需要提供全限定的Java类名,被指定的Java类必须实现JavaDelegate接口,但不需要实现序列化接口。Activiti在解析流程文件时,会将配置的值缓存起来,当流程到达Service Task时,会使用Java的反射
将类初始化,因此在实现JavaDelegate时,需要为其提供一个无参数的构造器,否则将抛出异常,提示无法进行实例化。
代码中定义了两个Service Task,同时使用了activiti:class属性,指定了同样的JavaDelegate,代码清单12-22为对应的JavaDelegate类的实现以及运行代码。
<process id="process1" name="process1">
<startEvent id="startevent1" name="Start"></startEvent>
<serviceTask id="servicetask1" name="Service Task 1"
activiti:class="pers.zhang.delegate.MyJavaDelegate"></serviceTask>
<serviceTask id="servicetask4" name="Service Task 2"
activiti:class="pers.zhang.delegate.MyJavaDelegate"></serviceTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="startevent1"
targetRef="servicetask1"></sequenceFlow>
<sequenceFlow id="flow6" name="" sourceRef="servicetask1"
targetRef="servicetask4"></sequenceFlow>
<sequenceFlow id="flow7" name="" sourceRef="servicetask4"
targetRef="endevent1"></sequenceFlow>
</process>
public class MyJavaDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) {
System.out.println("实现JavaDelegate的JavaServiceTask:" + this);
}
}
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
repositoryService.createDeployment().addClasspathResource("demo12/ImplementServiceTask.bpmn").deploy();
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1");
实现JavaDelegate的JavaServiceTask:pers.zhang.delegate.MyJavaDelegate@724bade8
实现JavaDelegate的JavaServiceTask:pers.zhang.delegate.MyJavaDelegate@16fb356
根据输出的结果可以看出,使用这种方式,每次都会为JavaDelegate创建新的实例。除了这种方法外,还可以使用activiti:delegateExpression属性结合JUEL表达式来配置执行的Java
类:activiti:delegateExpression="${myDelegate}"
,使用这种方法配置运行的Java类,同样需要实现JavaDelegate接口,但是创建JavaDelegate实例的过程将会交由提供者实现,提供者创建JavaDelegate的实例后,需要将这个实例设置到流程参数中。
<process id="process1" name="process1" isExecutable="true">
<startEvent id="startevent1" name="Start"></startEvent>
<serviceTask id="servicetask1" name="Service Task"
activiti:delegateExpression="${myDelegate}"></serviceTask>
<serviceTask id="servicetask2" name="Service Task"
activiti:delegateExpression="${myDelegate}"></serviceTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" sourceRef="startevent1"
targetRef="servicetask1"></sequenceFlow>
<sequenceFlow id="flow2" sourceRef="servicetask1"
targetRef="servicetask2"></sequenceFlow>
<sequenceFlow id="flow3" sourceRef="servicetask2"
targetRef="endevent1"></sequenceFlow>
</process>
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
repositoryService.createDeployment().addClasspathResource("demo12/JUELClass.bpmn").deploy();
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("myDelegate", new MyJavaDelegate());
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1", vars);
实现JavaDelegate的JavaServiceTask:pers.zhang.delegate.MyJavaDelegate@2427e004
实现JavaDelegate的JavaServiceTask:pers.zhang.delegate.MyJavaDelegate@2427e004
根据输出结果可以看出,每次执行输出的均为同一个实例,因为使用对象作为流程参数,所以会将该对象序列化并保存到资源表中,该参数会一直存在,直到流程结束。
4.3、使用普通JavaBean
除了可以使用JavaDelegate的实现类来指定Service Task外,还可以使普通的Java Bean作为执行的程序,使用方法与使用JUEL表达式分配用户任务权限类似:${myBean.method(}
,除了可以使用这种形式来调用Java方法外,还可以调用JavaBean的属性,并且将其设置到流
程参数中:
<process id="process1" name="process1">
<startEvent id="startevent1" name="Start"></startEvent>
<endEvent id="endevent1" name="End"></endEvent>
<serviceTask id="servicetask1" name="Service Task"
activiti:expression="${myBean.print(execution)}"></serviceTask>
<serviceTask id="servicetask2" name="Service Task"
activiti:expression="${execution.setVariable('myName', myBean.name)}"></serviceTask>
<sequenceFlow id="flow1" name="" sourceRef="startevent1"
targetRef="servicetask1"></sequenceFlow>
<sequenceFlow id="flow2" name="" sourceRef="servicetask1"
targetRef="servicetask2"></sequenceFlow>
<userTask id="usertask1" name="End Task"></userTask>
<sequenceFlow id="flow3" name="" sourceRef="servicetask2"
targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow4" name="" sourceRef="usertask1"
targetRef="endevent1"></sequenceFlow>
</process>
public class MyJavaBean implements Serializable {
private String name = "crazyit";
public String getName() {
return name;
}
public void print(Execution exe) {
System.out.println("使用Java Bean的print方法:" + exe.getId());
}
}
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
repositoryService.createDeployment().addClasspathResource("demo12/JavaBeanServiceTask.bpmn").deploy();
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("myBean", new MyJavaBean());
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1", vars);
// 进行任务参数查询
System.out.println("运行两个Service Task的myName参数值为:"
+ runtimeService.getVariable(pi.getId(), "myName"));
使用Java Bean的print方法:25009
运行两个Service Task的myName参数值为:crazyit
4.4、在Activiti中调用Web Service
Web Service Task是BPMN的规范之一,从另外一个角度看,该任务实际上也是一个发送任务(Send Task),但由于在调用Web Service的过程中,也有可能产生返回值,因此将其归类为服务任务。
如果要在Activiti中调用外部系统的Web Service,也可以在JavaDelegate中实现。在Java中调用Web Service的方法有很多,例如使用Apache的commons-httpclient、Xfire、axis和CXF等。在Activiti中除了可以在JavaDelegate中调用Web Service外,还可以使用BPMN2.0的XML配置来实现Web Service的调用,将相应的Web Service信息放到流程配置文件中,研发人员无须关心Web Service的调用过程。
在Web Service Task中调用外部的Web Service,需要先了解Activiti的几个元素。
4.5、import元素
当流程文件中的内容需要使用到外部的元素时,可以使用import元素来声明一个外部元素定义,定义一个import需要提供以下3个属性。
- importType:外部元素的类型,例如外部的元素是遵守MLl.0规范的文档,那么需要将该值设置为http:/www.w3.org/200l/XMLSchema。
- location:外部元素所在的文档路径,如果需要调用Web Service,则提供的是wsdl的路径。
- namespace:该import元素的命名空间。
以下配置片断定义了一个import元素:
<import importType="http://schemas.xmlsoap.org/wsdl/" location="http://localhost:9090/sale?wsdl" namespace="http://webservice.activiti.crazyit.org/" />
4.6、itemDefinition和message元素
itemDefinition用于定义数据对象或者消息对象,这些对象可以在流程中操作、传输、转换或者存储,一个itemDefinition最重要的是它的结构,BPMN规范对这个数据结构并没有特别的要求,但是需要为其指定相应的语法规则,因此一个itemDefinition的结构会受其指定的语法规则所约束,默认情况下会使用XML作为itemDefinition的数据结构约束,即不指定数据结构规则的话,itemDefinitio需要遵守XML的语法规则。
message用于定义流程参与者之间的交互信息,因此每个message均有相应的格式,在BPMN2.0提供的XML规范中,定义Message的格式由itemDefinition完成,因此一个具有格式的message会引用一个定义好的itemDefinition。以下配置片断定义了一个itemDefinition和
一个message元素。
<message id="myMessage" itemRef="myItem"></message>
<itemDefinition id="myItem" structureRef="元素结构" />
以上的配置片断定义了一个id为“myItem”的itemDefinition,由于需要为itemDefinition指定数据结构约束,因此需要使用structureRef属性,而message元素则引用了itemDefinition。
在上一节中定义的import元素,其类型为wsdl,同时也提供了相应的wsdl和路径,如果在itemDefinition中配置structureRef,那么该structureRef所引用的元素结构必须要在相应的wsdl中体现。
4.7、interface与operation元素
interface元素用于定义服务接口,interface元素下可以定义多个operation元素,表示一个服务下的多个操作。如果有一个支付服务接口,在里面定义了支付明细查询、处理支付等操作,那么此时可以定义一个interface表示该支付服务,再为其定义支付明显细查询操作和处理支付操作。以下配置片断定义了一个interface和一个operation:
<interface name="Payment Service" implementationRef="WSDL中portType的名称">
<operation id="createPayment" name="Create Payment Operation" implementationRef="WSDL中的操作名称">
<inMessageRef>WSDL中操作的input message</inMessageRef>
<outMessageRef>WSDL中操作的output message</outMessageRef>
</operation>
</interface>
定义了一个operation之后,在使用Serice Task时,可以为serviceTask元素加入operationRef属性来指定该Service Task使用的操作。
4.8、设置Web Service参数与返回值
要定义Web Service的参数与返回值,可以在serviceTask元素中添加dataInputAssociation和dataOutputAssociation子元素,dataInputAssociation元素表示输入的参数,
dataOutputAssociation元素表示执行Web Service后的返回结果
<process id="process1" name="process1" isExecutable="true">
<serviceTask id="servicetask1" name="Web service invocation"
implementation="##WebService" operationRef="createSaleOper">
<dataInputAssociation>
<sourceRef>creatorVar</sourceRef>
<targetRef>creator</targetRef>
</dataInputAssociation>
<dataOutputAssociation>
<sourceRef>newSale</sourceRef>
<targetRef>saleVar</targetRef>
</dataOutputAssociation>
</serviceTask>
</process>
<itemDefinition id="newSale" structureRef="sale:sale" />
<itemDefinition id="saleVar" structureRef="string" />
<itemDefinition id="creatorVar" structureRef="string" />
<itemDefinition id="creator" structureRef="string" />
代码中定义了一个dataInputAssociation,该元素下有sourceRef和targetRef子元素,由于在调用时,流程引擎并不知道所传入的参数的数据结构,因此sourceRef和targetRef均需要引用相应的itemDefinition。定义了一个dataOutputAssociation,表示调用后产生的返回值,其中sourceRef定义返回值的数据结构,如果返回的是普通字符串,则可以引用代码中定义的itemDefinition,如果返回的是一个对象,则可以引用定义的itemDefinition。
4.9、发布Web Service
@WebService
public interface SaleService {
@WebMethod
@WebResult(name = "newSale")
Sale createSale(@WebParam(name = "creator")String creator,
@WebParam(name = "createDate")String createDate);
}
@WebService()
public class SaleServiceImpl implements SaleService {
public Sale createSale(String creator, String createDate) {
System.out.println("创建人:" + creator);
System.out.println("创建日期:" + createDate);
Sale sale = new Sale();
sale.setSaleCode("SA00001");
return sale;
}
}
使用@WebService注解发布一个SaleService,该SaleService中只
有一个接口方法,主要用于创建销售单对象(Sale),调用该方法需要传入creator和createDate参数,这两个参数均为字符串类型,在实现类中,只是输出两个参数,再创建一个Sale对象并返回。编写完Veb Service的实现代码后,再编写运行类,在main方法中启动Web容器并
发布代码清单12-29的Web Service,服务器类以及客户端类如代码所示。
public class Main {
public static void main(String args[]) throws Exception {
Endpoint e = Endpoint.publish("http://localhost:9090/sale", new SaleServiceImpl());
System.out.println("服务启动...");
}
}
public class CallClient {
public static void main(String[] args) throws Exception {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://localhost:9090/sale?wsdl");
Object[] vars = new Object[]{"crazyit", "2018-10-10 10:10:10"};
Object[] object = client.invoke("createSale", vars);
Sale sale = (Sale)object[0];
System.out.println("请求WebService后返回的销售单号:" + sale.getSaleCode());
}
}
4.10、使用Web Sercice Task
<import importType="http://schemas.xmlsoap.org/wsdl/" location="http://localhost:9090/sale?wsdl"
namespace="http://webservice.activiti.crazyit.org/" />
<process id="testProcess" name="testProcess">
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="usertask1" name="Ready Task"></userTask>
<serviceTask id="servicetask1" name="Web service invocation"
implementation="##WebService" operationRef="createSaleOper">
<dataInputAssociation>
<sourceRef>creatorVar</sourceRef>
<targetRef>creator</targetRef>
</dataInputAssociation>
<dataInputAssociation>
<sourceRef>createDateVar</sourceRef>
<targetRef>createDate</targetRef>
</dataInputAssociation>
<dataOutputAssociation>
<sourceRef>newSale</sourceRef>
<targetRef>saleVar</targetRef>
</dataOutputAssociation>
</serviceTask>
<userTask id="usertask2" name="EndTask"></userTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="startevent1"
targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow2" name="" sourceRef="usertask1"
targetRef="servicetask1"></sequenceFlow>
<sequenceFlow id="flow3" name="" sourceRef="servicetask1"
targetRef="usertask2"></sequenceFlow>
<sequenceFlow id="flow4" name="" sourceRef="usertask2"
targetRef="endevent1"></sequenceFlow>
</process>
<!-- 定义两个消息 -->
<message id="createSaleMsg" itemRef="tns:createSaleItem"></message>
<message id="createSaleResponseMsg" itemRef="tns:createSaleResponseItem"></message>
<!-- 定义两个item,用于定义消息的格式 -->
<itemDefinition id="createSaleItem" structureRef="sale:createSale" />
<itemDefinition id="createSaleResponseItem"
structureRef="sale:createSaleResponse" />
<!-- 定义item,在调用webservice时,需要指定参数与返回结果的结构 -->
<itemDefinition id="creatorVar" structureRef="string" />
<itemDefinition id="creator" structureRef="string" />
<itemDefinition id="createDateVar" structureRef="string" />
<itemDefinition id="createDate" structureRef="string" />
<itemDefinition id="newSale" structureRef="sale:sale" />
<itemDefinition id="saleVar" structureRef="string" />
<interface name="Sale Service" implementationRef="SaleService">
<operation id="createSaleOper" name="Create Sale Operation"
implementationRef="sale:createSale">
<!-- 输入消息与输出消息 -->
<inMessageRef>createSaleMsg</inMessageRef>
<outMessageRef>createSaleResponseMsg</outMessageRef>
</operation>
</interface>
public static void main(String[] args) {
// 创建流程引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 得到流程存储服务组件
RepositoryService repositoryService = engine.getRepositoryService();
// 得到运行时服务组件
RuntimeService runtimeService = engine.getRuntimeService();
// 得到任务服务组件
TaskService taskService = engine.getTaskService();
// 部署流程文件
repositoryService.createDeployment()
.addClasspathResource("bpmn/WebService.bpmn").deploy();
// 初始化参数
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("creatorVar", "angus");
vars.put("createDateVar", "2018-02-02 10:10:10");
ProcessInstance pi = runtimeService.startProcessInstanceByKey(
"testProcess", vars);
// 完成第一个任务
Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
taskService.complete(task.getId());
// 输出调用Web Service后的参数
Sale sale = (Sale) runtimeService.getVariable(pi.getId(), "saleVar");
System.out.println("请求创建销售单后,返回的销售单号:" + sale.getSaleCode());
}
4.11、JavaDelegate属性注入
使用BPMN的配置来调用Web Service,配置较为烦琐,因此可以考虑在自定义的JavaDelegate中直接调用Web Service。使用编码方式调用Web Service,需要知道wsdl路径、操作、请求参数和调用返回值等属性,如果将这些属性配置到流程文件中,那么就需要使用
JavaDelegate的属性注入。为一个JavaDelegate注入值有以下两种形式:字符串注入和表达式注入。对于一些常量,可以在流程文件中通过配置进行字符串注入,而对于一些变量或者对象,可以配置成JUEL表达式。
<process id="process1" name="process1">
<startEvent id="startevent1" name="Start"></startEvent>
<userTask id="usertask1" name="End Task"></userTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow3" name="" sourceRef="usertask1"
targetRef="endevent1"></sequenceFlow>
<serviceTask id="servicetask1" name="Service Task"
activiti:class="org.crazyit.activiti.StringInjectionDelegate">
<extensionElements>
<activiti:field name="userName" stringValue="Crazyit" />
<activiti:field name="passwd">
<activiti:string>123456</activiti:string>
</activiti:field>
</extensionElements>
</serviceTask>
<sequenceFlow id="flow4" name="" sourceRef="startevent1"
targetRef="servicetask1"></sequenceFlow>
<sequenceFlow id="flow5" name="" sourceRef="servicetask1"
targetRef="usertask1"></sequenceFlow>
</process>
public class StringInjectionDelegate implements JavaDelegate {
// 用户名属性
private Expression userName;
// 密码属性
private Expression passwd;
public void setUserName(Expression userName) {
this.userName = userName;
}
public void setPasswd(Expression passwd) {
this.passwd = passwd;
}
public void execute(DelegateExecution execution) {
// 输出属性
System.out.println("在JavaDelegate中注入字符串,userName值:"
+ userName.getValue(null) + ", passwd值:"
+ passwd.getValue(null));
}
}
public static void main(String[] args) {
// 创建流程引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 得到流程存储服务组件
RepositoryService repositoryService = engine.getRepositoryService();
// 得到运行时服务组件
RuntimeService runtimeService = engine.getRuntimeService();
// 部署流程文件
repositoryService.createDeployment()
.addClasspathResource("bpmn/StringInjection.bpmn").deploy();
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1");
}
除了可以注入字符串外,还可以使用JUEL表达式为JavaDelegate注入对象或者经过计算后的值:
<process id="process1" name="process1">
<startEvent id="startevent1" name="Start"></startEvent>
<serviceTask id="servicetask1" name="Service Task"
activiti:class="org.crazyit.activiti.ExpressionInjectionDelegate">
<extensionElements>
<activiti:field name="user" expression="${user}"></activiti:field>
<activiti:field name="amountResult">
<activiti:expression>${user.countAmount(amount)}</activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="startevent1"
targetRef="servicetask1"></sequenceFlow>
<sequenceFlow id="flow2" name="" sourceRef="servicetask1"
targetRef="endevent1"></sequenceFlow>
</process>
public class ExpressionInjectionDelegate implements JavaDelegate {
private Expression user;
private Expression amountResult;
public void setAmountResult(Expression amountResult) {
this.amountResult = amountResult;
}
public void setUser(Expression user) {
this.user = user;
}
@Override
public void execute(DelegateExecution execution) {
UserBean userBean = (UserBean) user.getValue(execution);
System.out.println("在JavaDelegate中注入对象:" + userBean.getName() + " "
+ userBean.getPasswd());
System.out.println("使用UserBean的方法计算后结果::"
+ amountResult.getValue(execution));
}
}
public static void main(String[] args) {
// 创建流程引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 得到流程存储服务组件
RepositoryService repositoryService = engine.getRepositoryService();
// 得到运行时服务组件
RuntimeService runtimeService = engine.getRuntimeService();
// 部署流程文件
repositoryService.createDeployment()
.addClasspathResource("bpmn/ExpressionInjection.bpmn").deploy();
// 初始化参数
Map<String, Object> vars = new HashMap<String, Object>();
UserBean user = new UserBean("crazyit", "123456");
vars.put("user", user);
vars.put("amount", 10);
// 启动流程
runtimeService.startProcessInstanceByKey("process1", vars);
}
4.12、在JavaDelegate中调用Web Service
可以将Web Service的相关信息动态化,以设置到流程变量中。调用一个Web Service需要wsdl路径、请求参数、操作名称(方法等)。
public static void main(String[] args) throws Exception {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://localhost:9090/sale?wsdl");
Object[] vars = new Object[]{"crazyit", "2018-10-10 10:10:10"};
Object[] object = client.invoke("createSale", vars);
Sale sale = (Sale)object[0];
System.out.println("请求WebService后返回的销售单号:" + sale.getSaleCode());
}
<process id="JavaDelegateWebService" name="JavaDelegateWebService">
<startEvent id="startevent1" name="Start"></startEvent>
<serviceTask id="servicetask1" name="Service Task"
activiti:class="org.crazyit.activiti.WebServiceDelegate">
<extensionElements>
<activiti:field name="wsdl"
stringValue="http://localhost:9090/sale?wsdl" />
<activiti:field name="operation" stringValue="createSale" />
<activiti:field name="creator" stringValue="crazyit" />
<activiti:field name="createDate" stringValue="2018-10-10 10:10:10" />
</extensionElements>
</serviceTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="startevent1"
targetRef="servicetask1"></sequenceFlow>
<sequenceFlow id="flow2" name="" sourceRef="servicetask1"
targetRef="endevent1"></sequenceFlow>
</process>
public class WebServiceDelegate implements JavaDelegate {
private Expression wsdl;
private Expression operation;
private Expression creator;
private Expression createDate;
public void setWsdl(Expression wsdl) {
this.wsdl = wsdl;
}
public void setOperation(Expression operation) {
this.operation = operation;
}
public void setCreator(Expression creator) {
this.creator = creator;
}
public void setCreateDate(Expression createDate) {
this.createDate = createDate;
}
public void execute(DelegateExecution execution) {
try {
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
// 使用wsdl路径创建Client
Client client = dcf.createClient((String) wsdl.getValue(null));
// 使用配置的值创建参数对象
Object[] vars = new Object[] { creator.getValue(null),
createDate.getValue(null) };
// 调用
Object[] object = client
.invoke((String) operation.getValue(null), vars);
Sale sale = (Sale) object[0];
System.out.println("在JavaDelegate中调用Web Service后,结果: "
+ sale.getSaleCode());
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.13、Shell任务
public class JavaShell {
public static void main(String[] args) throws Exception {
//创建命令集合
List<String> argList = new ArrayList<String>();
argList.add("cmd");
argList.add("/c");
argList.add("echo");
argList.add("hello");
argList.add("crazyit");
ProcessBuilder processBuilder = new ProcessBuilder(argList);
// 执行命令返回进程
Process process = processBuilder.start();
// 解析输出
String result = convertStreamToStr(process.getInputStream());
System.out.println(result);
}
//读取输出流并转换为字符串
public static String convertStreamToStr(InputStream is) throws IOException {
if (is != null) {
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
Reader reader = new BufferedReader(new InputStreamReader(is,
"UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} finally {
is.close();
}
return writer.toString();
} else {
return "";
}
}
}
main方法创建一个字符串集合,然后向其中添加需要执行的命令,
由于使用的是Windows操作系统,因此需要先执行“cmd”命令进入命令行,“/c”表示执行完成后关闭窗口,从第三条命令开始,表示在命令行中输出“hello crazyit”。使用ProcessBuilder的start方法启动进程后,会返回一个Process对象,然后使用convertStreamToStr方法读取Process对象的输出流并转换为字符串,最后输出到控制台中,运行代码最终输出结果为:hello crazyit。.
代码的逻辑是,Activiti的Shell Task已经实现,Activiti中为Service Task设置执行类,可以通过设置JavaDelegate类实现,也可以通过设置ActivityBehavior类来实现,ShellTask就是使用Activiti内置的ActivityBehavior实现类来执行Shell命令的,因此,在配置一个
Shell Task时,需要告诉它执行参数,这些参数包括
- command:执行的Shel命令,命令字符串集合的第一个元素,必须提供该参数。
- argl-5:执行的命令参数,字符串集合中的第2~6个元素,为可选参数。
- wait:是否等待命令执行完成,为可选参数,默认为true。
- redirectError:是否合并错误输出和标准输出,为可选参数,默认为false。
- cleanEnv:执行命令前是否清空当前进程的环境变量信息,默认为false。
- outpuVariable:如果配置该值,则将执行命令的输出作为流程参数存到流程中。
- errorCodeVariable:如果配置该值,则将执行命令的进程errorCode存到流程参数中。
- directory:设置此命令的工作目录,默认为当前目录。
这些参数均为字符串类型,为一个JavaDelegate或者ActivityBehavior进行属性注入,只需要使用activiti:field元素并配置stringValue即可。
<process id="process1" name="process1">
<startEvent id="startevent1" name="Start"></startEvent>
<serviceTask id="servicetask1" name="Service Task" activiti:type="shell">
<extensionElements>
<activiti:field name="command" stringValue="cmd"/>
<activiti:field name="arg1" stringValue="/c"/>
<activiti:field name="arg2" stringValue="echo"/>
<activiti:field name="arg3" stringValue="%JAVA_HOME%"/>
<activiti:field name="outputVariable" stringValue="javaHome"/>
</extensionElements>
</serviceTask>
<endEvent id="endevent1" name="End"></endEvent>
<sequenceFlow id="flow1" name="" sourceRef="startevent1"
targetRef="servicetask1"></sequenceFlow>
<userTask id="usertask1" name="End Task"></userTask>
<sequenceFlow id="flow2" name="" sourceRef="servicetask1"
targetRef="usertask1"></sequenceFlow>
<sequenceFlow id="flow3" name="" sourceRef="usertask1"
targetRef="endevent1"></sequenceFlow>
</process>
// 创建流程引擎
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
// 得到流程存储服务组件
RepositoryService repositoryService = engine.getRepositoryService();
// 得到运行时服务组件
RuntimeService runtimeService = engine.getRuntimeService();
// 部署流程文件
repositoryService.createDeployment()
.addClasspathResource("bpmn/ShellTask.bpmn").deploy();
// 启动流程
ProcessInstance pi = runtimeService
.startProcessInstanceByKey("process1");
// 查询流程参数
System.out.println("运行Shell Task得到JAVA_HOME的环境变量值为:"
+ runtimeService.getVariable(pi.getId(), "javaHome"));