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代码来完成业务的流转。