本文开始重新回归一些activiti的基本使用。感觉前面太想展开源码和架构方面的探讨,但在这过程中,又涉及到activiti很多基本的用法我没有熟练使用,例如表达式、网关、多实例任务、作业、边界事件等等。导致在探讨源码的时候常常一笔带过,虽然对整体理解没有太大的问题,但是总感觉缺了点什么。所以后续决定也要熟练这些基本功能的使用。毕竟很多业务场景还是需要使用这些功能的。
activiti使用UEL处理表达式。UEL(Unified Expression Language)是EE6规范的一部分。activiti使用JUEL以支撑所有的运行环境及最新的UEL规范。
表达式可以用在很多场景中,例如ServiceTask、执行监听器、任务监听器以及连线的条件上。
表达式 | 表达式含义 |
${param} | 获取变量param的值 |
${param.age} | 获取对象param的age属性的值 |
${param.test()} | 调用对象param的test方法 |
${param.test("hello")} | 调用对象param的test方法,参数为字符串"hello" |
除了上面所说的这些表达式,还有以下三种流程引擎的内置变量
变量名称 | 变量含义 |
task | 通过此变量可以获取用户任务相关的属性。实现了DelegateTask接口 |
execution | 通过此变量可以获取流程实例的信息。实现了DelegateExecution接口 |
authenticatedUserId | 在启动流程时调用IdentityService的setAuthenticatedUserId方法设置 |
现在有个场景,新建一个请假流程,员工提交给经理审批,流程到员工待办和到经理待办时都有提示,流程结束时也会提示流程完成。
这个例子我们使用系列文章最简单的activiti.cfg.xml作为流程引擎配置文件,在《activiti学习(一)——activiti流程引擎的配置与初始化操作》中查找。流程文档expressBPM.bpmn如下:
第5行usertask1节点通过${employee}表达式设置assignee。第7行为usertask1新增一个监听create事件的任务监听器,使用expression方式创建,调用notice对象的callEmployee方法,并把task内置变量作为参数传入。第11行usertask2节点通过${manager}表达式设置assignee。13行为usertask2新增一个监听create事件的任务监听器,使用delegateExpression方式创建,监听器对象为${callManager}变量。19行为endevent1节点新增一个监听end事件的执行监听器,调用notice对象的callComplete方法,并把execution内置变量作为参数传入。流程图本身并不复杂,但添加了几个监听器,并使用了表达式,初学者可能有点乱。
现在我们创建一个Notice类,将来把它的实例作为流程变量notice传入。这个类作为expression创建任务监听器的处理类,这种处方式不需要创建监听器类,只需要在流程变量中传入指定类的对象即可等待activiti调用对象的指定方法:
public class Notice implements Serializable{
public void callEmployee(DelegateTask task) {
String assignee = (String)task.getVariable("employee");
System.out.println(assignee + " 有一个新的待办");
}
public void callComplete(DelegateExecution execution) {
System.out.println(execution.getProcessBusinessKey() + " 流程完成");
}
}
Notice类的实例因为要作为流程变量传入,所以必须实现Serializable接口。我们定义callEmployee和callComplete方法,分别表示通知员工有新待办和通知流程结束。注意这两个方法的参数,它们是通过内置变量task和execution传入,可往回查看流程文档对应的地方。
接下来创建一个ManagerListener,作为usertask2的任务监听器。这个类作为delegateExpression方法创建任务监听器的处理类,和class方式创建的任务监听器差不多,区别是class方式需指定具体类,而delegateExpression方式则是通过流程变量指定:
public class ManagerListener implements TaskListener{
public void notify(DelegateTask delegateTask) {
String assignee = delegateTask.getAssignee();
System.out.println(assignee + "经理有待办需要审批");
}
}
这里notify实现很简单,就是简单输出某某精力有待办的提示。
下面是我们的客户调用,App.java
public class App {
private ProcessEngine pe;
public void getFromProcessEngineConfiguration() {
ProcessEngineConfiguration pec = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
pe = pec.buildProcessEngine();
}
public void deploy() {
RepositoryService repositoryService = pe.getRepositoryService();
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
InputStream inputStream = null;
try {
inputStream = App.class.getClassLoader().getResource("bpmn/expressBPM.bpmn").openStream();
deploymentBuilder.addInputStream("express.bpmn", inputStream);
deploymentBuilder.name("expressDeployment");
Deployment deployment = deploymentBuilder.deploy();
System.out.println("部署完成");
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
App app = new App();
app.getFromProcessEngineConfiguration();
app.deploy();
}
}
5-9行为初始化流程引擎。11-25行为部署流程文档。这个和以前没什么区别,部署流程文档之后,查看数据库的情况,查看act_re_procdef:
接下来我们添加启动函数并调用之:
public void startProcessByIdWithVars() {
RuntimeService runtimeService = pe.getRuntimeService();
Notice notice = new Notice();
String businessKey = "请假单01";
Map vars = new HashMap();
vars.put("employee", "张三");
vars.put("notice", notice);
ProcessInstance pi = runtimeService.startProcessInstanceById("expressProcess:1:4", businessKey, vars);
System.out.println("流程开始");
}
第7-8行把notice作为流程变量,并在启动流程时添加进去。此时控制台输出:
可以看到流程已经成功调用Notice的callEmployee方法,使用expression创建监听器成功。此时act_re_task表:
接着定义一个employeeCompleteTask,员工环节提交的方法并调用之:
public void employeeCompleteTask() {
TaskService taskService = pe.getTaskService();
TaskListener taskListener = new ManagerListener();
Map vars = new HashMap();
vars.put("callManager", taskListener);
vars.put("manager", "李四");
taskService.complete("2508", vars);
System.out.println("完成提交");
}
第5行设置ManagerListener到callManager变量中,第6行把“李四”设置到“manager”变量中。执行后看看控制台输出:
可以看到已经成功触发了任务监听器ManagerListener,通过delegateExpression创建监听器成功。再看此时act_re_task表:
接下来定义经理审批方法manageCompleteTask并调用之:
public void manageCompleteTask() {
TaskService taskService = pe.getTaskService();
TaskListener taskListener = new ManagerListener();
Map vars = new HashMap();
taskService.complete("5006", vars);
System.out.println("完成提交");
}
执行该方法,正常来说流程结束。此时看看控制台:
可以看到已经成功触发Notice的callComplete方法。
到目前为止我们已经掌握表达式的基本用法,并把它使用在任务监听器、执行监听器以及设置assignee。在ServiceTask、连线条件上的使用大同小异,请读者自行学习,后面的文章中也会进行使用。