activiti学习(十五)——表达式的使用

本文开始重新回归一些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如下:

activiti学习(十五)——表达式的使用_第1张图片



  
    
    
      
        
      
    
    
    
      
        
      
    
    
    
      
        
      
    
    
  
  
    
      
        
      
      
        
      
      
        
      
      
        
      
      
        
        
      
      
        
        
      
      
        
        
      
    
  

第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、连线条件上的使用大同小异,请读者自行学习,后面的文章中也会进行使用。

你可能感兴趣的:(Activiti)