Flowable本地配置开发


Flowable

Flowable是一个基于Java开发的开源的企业流程engine,因为项目需要使用flowable作为一个流转平台,所以再本地搭载了一个平台进行测试,主要使用Tomcat及JAVA,并且测试了如何使用java调用Python代码,所以我们可以使用Python实现相应的业务逻辑,并使用Java调用Python代码来进行业务流程流转。如果想详细了解Flowable可以参考Flowable Start. Flowable支持REST调用

下载Tomcat

可以通过官网下载相应的binary版本然后进行解压。

下载Flowable

可以下载最新版本的Flowable的binary file,下载到本地并进行解压。解压之后的最要的是再文件夹wars里面的2个对应的war文件,flowable-ui.war是用来启动UI,flowable-rest.war是用来提供REST支持。

启动flowable页面

在启动Tomcat之前,我们需要将解压的Flowable的wars里面的两个war文件复制到tomcat的webapps的文件夹里面,然后我们可以打开一个terminal(windows直接cmd),进入到Tomcat的bin文件夹里面,输入catalina run,Tormcat则会将全部的webapps里面的war文件运行,启动完毕之后可以可以在本地浏览器输入http://localhost:8080/flowable-ui,我们就可以进入到flowable的可视化的app网站。默认的用户名是admin, 密码是test

Java代码实现Flowable业务流转

Java调用Flowable core

以一个简单的员工申请休假领导进行批准的例子,以下为相应的java代码:

package process_engine.build.test;

import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Scanner;

import org.flowable.engine.HistoryService;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;


public class BuildFirstClass {
	public static void main(String[] args) {
		// First to build a configuration
		ProcessEngineConfiguration pec = new StandaloneProcessEngineConfiguration()
				.setJdbcUrl("jdbc:h2:mem:flowable;DB_CLOSE_DELAY=-1")
				.setJdbcUsername("sa")
				.setJdbcPassword("")
				.setJdbcDriver("org.h2.Driver")
				.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
		
		// create process engine based on configuration
		ProcessEngine peEngine = pec.buildProcessEngine();
		
		// get service by creating a deployment and read the XML files.
		RepositoryService repositoryService = peEngine.getRepositoryService();
		Deployment deployment = repositoryService
				.createDeployment()
				.addClasspathResource("holiday-request.bpmn20.xml")
				.deploy();
		
		// query the result
		ProcessDefinition processDefinition = repositoryService
				.createProcessDefinitionQuery()
				.deploymentId(deployment.getId()).singleResult();
		
		System.out.println("Get process definition:" + processDefinition.getName());
		
		// provide with some variables by keyboard input.
		Scanner scanner = new Scanner(System.in);
		System.out.println("Who are you?");
		String employString = scanner.nextLine();
		
		System.out.println("How many days do you need?");
		Integer daysInteger = Integer.valueOf(scanner.nextLine());
		
		System.out.println("Why do you need?");
		String descString = scanner.nextLine();
		
		
		// start a process engine
		RuntimeService runtimeService = peEngine.getRuntimeService();
		HashMap variables = new HashMap();
		variables.put("employee", employString);
		variables.put("nrOfHolidays", daysInteger);
		variables.put("description", descString);
		
		// which flow to process?
		ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holidayRequest", variables);
		
		// get full task list based on which group to use?
		TaskService taskService = peEngine.getTaskService();
		List tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();
		
		System.out.println("You have "+ tasks.size() + " tasks:");
		for (int i = 0; i < tasks.size(); i++) {
			System.out.println(tasks.get(i).getName());
		}
		
		System.out.println("Which task would you love to process?");
		int taskindex = Integer.valueOf(scanner.nextLine());
		
		Task task = tasks.get(taskindex- 1);
		Map processvaluesMap = taskService.getVariables(task.getId());
		
		System.out.println(processvaluesMap.get("employee") + " wants " +
				processvaluesMap.get("nrOfHolidays") + " of holidays for reason: '"+ processvaluesMap.get("description") +
				"' Do you approve this request?");
		
		String approveString = scanner.nextLine().toLowerCase();
		boolean approve;
		if (approveString.toLowerCase().equalsIgnoreCase("y") | approveString.equalsIgnoreCase("yes")){
			approve = true;
		}else {
			approve = false;
		}
		
//		boolean approve = scanner.nextLine().toLowerCase().equals("1");
		variables = new HashMap();
		variables.put("approved", approve);
		taskService.complete(task.getId(), variables);
		//System.out.println("get approve status:" + approve);
		
		// Test with historical data that in stored in the DB
//		HistoryService historyService = peEngine.getHistoryService();
//		List listActivityInstances = historyService.createHistoricActivityInstanceQuery()
//				.processDefinitionId(processInstance.getActivityId())
//				.finished()
//				.orderByHistoricActivityInstanceEndTime()
//				.asc()
//				.list();
//		
//		for (HistoricActivityInstance historicActivityInstance: listActivityInstances) {
//			System.out.println(historicActivityInstance.getActivityId() + " took " + historicActivityInstance.getDurationInMillis() + " milli seconds");
//		}
	}

}

JAVA调用Python

我们可以编写另一个类来调用我们的python代码,流程的流转主要依赖于XML文件定义。

package process_engine.build.test;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;


class RunPython{
	Process process;
	public void runPython() {
		try {
			// I have also test that we could try to fit a model, so the logic here is that we
			// try to call a process to run code with python engine and will wait until finished.
			process = Runtime.getRuntime().exec("C:\\Users\\Public\\anaconda\\python.exe C:\\Users\\sample.py");
			process.waitFor();
		} catch (Exception e) {
			// TODO: handle exception
			System.err.println("Get error to call Python code: " + e);
		}
		InputStream inputStream = process.getInputStream();
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
		String lineString;
		try {
			while ((lineString = bufferedReader.readLine()) != null) {
				System.out.println("get Python output: " + lineString);
			}
		} catch (Exception e) {
			// TODO: handle exception
			System.err.println("get python output error:" + e);
		}
		
	}
}


public class CallExternalSystemDelegate implements JavaDelegate{
	
	// if we implement this func, then will be called based on xml file in process step.
	public void execute(DelegateExecution execution) {
		// TODO Auto-generated method stub
		System.err.println("Now try to call external system for " + execution.getVariable("employee"));
		
		// Here just to test how to call python code here with Java!
		RunPython runPython =new RunPython();
		runPython.runPython();
		System.out.println("Finished for External Parts!");
	}
	
//	public static void main(String[] args) {
//		RunPython runPython = new RunPython();
//		runPython.runPython();
//	}
}

XML流转

需要创建一个xml文件描述

<?xml version="1.0" encoding="UTF-8"?>


  

    
    

	
	
	
	

    
    
      
        
      
    
    
      
        
      
    

	
	
    

	
    

    
    

    

    

  


运行Java类

在我们输入相应的信息之后我们可以在Console看到对应的结果:

最后一句

现在主要是使用Flowable利用Java代码来运行flowable,并且可以证明我们可以使用Java代码来调用Python代码来完成业务的流转。