一、JBPM(java business process manager)
1、工作流管理流程
O--->定义工作流(使用流程设计器生成,png和xml文件,分别面向用户和系统)
--->执行工作流(核心对象:流程引擎ProcessEngine)
--->连接数据库(jbpm18张表,jbpm4_deploymen,jbpm4_deployprop,jbpm4_execution,jbpm4_hist_task,jbpm_hist_var,jbpm4_lob,jbpm4_task,jbpm_variable)
<---O
2、jbmp中的几个基本概念
流程引擎,ProcessEnginee
*RepositoryService
*ExcutionService
*TaskService
部署对象(deployment):一次部署一个或者多个文件到数据库中(png,xml,zip)
流程定义(processDefinition):获得并解析xml,解析xml文件中的内容,内容即流程定义的规则,工作流jbpm就是按照流程定义的规则往下执行的。与流程定义相关的表,
jbpm部署流程定义的表:select * from jbpm4_deployment;
jbpm流程定义的表:select * from jbpm4_deployprop;
存放资源文件的表:select * from jbpm4_lob;
执行对象(Execution):按照指定的流程定义执行一次的过程,就叫做执行对象;
相关的数据库表:
存放jbpm正在执行的流程实例信息表:select * from jbpm4_execution;
存放jbpm执行信息流失表:select * from jbpm4_hist_procinst;
流程实例(ProcessInstance):从业务的开始到结束之间最大的执行对象就是流程实例,当业务流程中只有一个分支(路线)的时候,此时的执行对象就是流程实例。
流程变量:使用流程变量存储数据,在流程执行或者任务执行的过程中,用于设置和获取变量,使用流程变量在流程传递的过程中传递业务参数。
活动环节:
任务(Task)
当前活动节点是任务的时候,那么此时执行的就是任务
相关的数据库表:
存放正在执行的任务信息表:select * from jbpm4_task;
存放任务信息历史表:select * from jbpm4_hist_task;
状态(state)
当前活动节点是状态的时候,那么此时就是状态节点,是当前流程在状态节点中先停 留一下。
流程连线
1、一个活动中可以指定一个或多个Transition(Start中只能有一个,End中没有)
2、结束活动中没有Transition
3、开始活动中只有一个Transition
4、其他活动中有1条或多条Trasition
5、如果只有一个,则可以不指定名称(名称是null);如果有多个,则要分别指定唯一的名称。
2、jbpm的实现步骤和细节
四个步骤:
1、部署流程定义(xml和png)
2、启动流程实例
3、查看我的个人任务
4、办理任务
流程引擎的创建:
第一种:使用默认的配置文件(jbpm.cfg.xml)生成Configuration并构建ProcessEngine: ProcessEngine processEngine = new Configuration().buildProcessEngine(); 第二种:使用指定的配置文件(要放到classPath下): ProcessEngine processEngine = new Configuration() .setResource("my-own-configuration-file.xml") .buildProcessEngine(); 第三种:使用如下代码获取使用默认配置文件的、单例的ProcessEngine对象: ProcessEngine processEngine = Configuration.getProcessEngine();
流程定义:
1、部署流程定义
流程定义通过流程设计器设计出两个对应的png图片格式和xml配置文件的格式。
// 部署 @Test public void testDeploy() throws Exception { String deploymentId = processEngine.getRepositoryService()// .createDeployment()// .addResourceFromClasspath("helloworld/helloworld.jpdl.xml")// .addResourceFromClasspath("helloworld/helloworld.png")// .deploy(); System.out.println("deploymentId=" + deploymentId); } // 部署 @Test public void testDeploy_zip() throws Exception { InputStream in = getClass().getClassLoader().getResourceAsStream( "helloworld/helloworld.zip"); ZipInputStream zipInputStream = new ZipInputStream(in); String deploymentId = processEngine.getRepositoryService()// .createDeployment()// .addResourcesFromZipInputStream(zipInputStream)// .deploy(); System.out.println("deploymentId=" + deploymentId);
2、流程定义的查询
@Test public void testFindAll() throws Exception { // 查询 List<ProcessDefinition> list = processEngine.getRepositoryService()// .createProcessDefinitionQuery()// // 过滤条件 // .processDefinitionId("helloworld-1")// .processDefinitionKey("helloworld")// // 排序 // .orderAsc(ProcessDefinitionQuery.PROPERTY_ID)// // .orderDesc(ProcessDefinitionQuery.PROPERTY_VERSION)// // 执行查询 // .uniqueResult(); // .count(); // .page(firstResult, maxResults)// .list(); // 显示 for (ProcessDefinition pd : list) { System.out.println("id=" + pd.getId()// 格式:{key}-{version} + ", name=" + pd.getName()// .jpdl.xml根元素的name属性的值 + ", key=" + pd.getKey()// .jpdl.xml根元素的key属性的值,如果不写,默认为name属性的值 + ", version=" + pd.getVersion()// 默认自动维护,第1个是1,以后相同key的都会自动加1 + ", deploymentId=" + pd.getDeploymentId()); // 所属的某个Deployment的对象 } }
3、删除流程定义
// 删除(使用流程定义ID) @Test public void testDeleteById() throws Exception { String deploymentId = "90001"; // 删除某部署对象(也可以称之为删除流程流程定义),如果有关联的执行信息,就报错 // processEngine.getRepositoryService().deleteDeployment(deploymentId); // 删除某部署对象(也可以称之为删除流程流程定义),如果有关联的执行信息,就级联删除 processEngine.getRepositoryService().deleteDeploymentCascade( deploymentId); }
4、查看流程图
// 查看流程图(xxx.png) @Test public void testShowProcessImage() throws Exception { // 获取文件内容 String deploymentId = "1"; String resourceName = "helloworld/helloworld.png"; InputStream in = processEngine.getRepositoryService()// .getResourceAsStream(deploymentId, resourceName); // 保存到c:/ FileOutputStream out = new FileOutputStream("c:/process.png"); for (int b = -1; (b = in.read()) != -1;) { out.write(b); } in.close(); out.close(); }
5、查询最新版本的流程定义
@Test public void testFindAllLatestVersions() throws Exception { // 查询,把最大的版本都排到后面 List<ProcessDefinition> list = processEngine.getRepositoryService()// .createProcessDefinitionQuery()// .orderAsc(ProcessDefinitionQuery.PROPERTY_VERSION)// .list(); // 过滤出最新的版本 Map<String, ProcessDefinition> map = new LinkedHashMap<String, ProcessDefinition>(); for (ProcessDefinition pd : list) { map.put(pd.getKey(), pd); } // 显示 for (ProcessDefinition pd : map.values()) { System.out.println("id=" + pd.getId()// 格式:{key}-{version} + ", name=" + pd.getName()// .jpdl.xml根元素的name属性的值 + ", key=" + pd.getKey()// .jpdl.xml根元素的key属性的值,如果不写,默认为name属性的值 + ", version=" + pd.getVersion()// 默认自动维护,第1个是1,以后相同key的都会自动加1 + ", deploymentId" + pd.getDeploymentId()); // 所属的某个Deployment的对象 } }
6、按照key删除所有版本的流程定义
// 删除(使用流程定义的key) @Test public void testDeleteByKey() throws Exception { // 1,查询指定key的所有版本的流程定义 List<ProcessDefinition> list = processEngine.getRepositoryService()// .createProcessDefinitionQuery()// .processDefinitionKey("helloworld")// .list(); // 2,循环删除 for (ProcessDefinition pd : list) { processEngine.getRepositoryService()// .deleteDeploymentCascade(pd.getDeploymentId()); } }
流程实例和任务
1、部署流程定义(xml和png)
2、启动流程实例
// 启动流程实例 @Test public void testStartProcessInstance() throws Exception { ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey("test"); System.out.println("流程实例启动成功,processInstanceId=" + pi.getId()); }
3、查看我的任务列表
@Test public void testFindMyTaskList() throws Exception { // 查询 String userId = "部门经理"; // List<Task> list = processEngine.getTaskService().findPersonalTasks(userId); List<Task> list = processEngine.getTaskService()// .createTaskQuery()// .assignee(userId)// 要是指定的办理人 // .count() // .page(firstResult, maxResults) .list(); // 显示 for (Task task : list) { System.out.println("id=" + task.getId()// + ", name=" + task.getName()// 任务的名称 + ", assignee=" + task.getAssignee()// 任务的办理人 + ", createTime=" + task.getCreateTime()// 任务的创建时间 + ", executionId=" + task.getExecutionId()); // 所属的执行对象的id } }
4、完成任务
// 办理任务 @Test public void testCompleteTask() throws Exception { String taskId = "20002"; processEngine.getTaskService().completeTask(taskId); }
5、向后执行一步
// 让流程向后执行一步 @Test public void testSignalExecution() throws Exception { //String executionId = "helloworld.20001"; //String signalName = "to 审批 [总经理]"; String executionId = "helloworld.20001"; processEngine.getExecutionService().signalExecutionById(executionId,"to 审批 [总经理]"); }
流程变量
1、在流程传递的过程中,可以为执行的对象或者任务来指定变量值,在流程执行、或者是任务执行的过程中,可以获取并设置对应的流程变量的值、
2、select * from jbmp4_variable
设置流程变量
// 设置流程变量 @Test public void testSetVariable() throws Exception { String executionId = "test.80001"; String name = "请假天数"; Object value = new Integer(5); processEngine.getExecutionService().setVariable(executionId, name, value); //Form form = new Form(1L, "张三请假11天"); //processEngine.getExecutionService().setVariable(executionId, "form", form); }
获取流程变量
// 获取流程变量 @Test public void testGetVariable() throws Exception { String executionId = "test.80001"; String name = "请假天数"; Object value = processEngine.getExecutionService().getVariable(executionId, name); System.out.println(name + " = " + value); //Form form = (Form) processEngine.getExecutionService().getVariable(executionId, "form"); //System.out.println("id=" + form.getId() + ", title=" + form.getTitle()); }
{ // ExecutionService executionService = processEngine.getExecutionService(); // TaskService taskService = processEngine.getTaskService(); // // ======================================== // // 设置变量的方法 // // 通过Execution设置一个变量 // executionService.setVariable(executionId, name, value); // // 通过Execution设置多个变量 // executionService.setVariables(executionId, variablesMap); // // 通过Task设置多个变量 // taskService.setVariables(taskId, variablesMap); // // 在启动流程实例时,同时也设置一些流程变量 // executionService.startProcessInstanceByKey(processDefinitionKey, variablesMap); // // 在完成任务时,同时也设置一些流程变量 // taskService.completeTask(taskId, variablesMap); // // ======================================== // // 获取变量的方法 // // 通过Execution获取一个变量 // executionService.getVariable(executionId, variableName); // // 通过Execution获取所有变量的名称集合 // executionService.getVariableNames(executionId); // // 通过Execution获取所有变量的信息 // executionService.getVariables(executionId, variableNames); }
流程连线和活动
1、判断decision
URL url = this.getClass().getResource("test.jpdl.xml"); String deploymentID = processEngine.getRepositoryService()// .createDeployment()// .addResourceFromUrl(url)// .deploy(); System.out.println("部署流程定义成功!deploymentID"+deploymentID); //Integer value = 300; Integer value = 3000; Map<String, Object> variables = new HashMap<String, Object>(); variables.put("报销金额", value); ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey("test",variables); System.out.println("启动流程实例成功!id="+pi.getId()); Task task = processEngine.getTaskService()// .createTaskQuery()// .processInstanceId(pi.getId())// .uniqueResult(); System.out.println("当前任务的ID="+task.getId()); System.out.println("当前任务的名称="+task.getName()); processEngine.getTaskService().completeTask(task.getId()); System.out.println("任务完成!");
判断当前操作属于哪一个分支
@SuppressWarnings("serial") public class DecisionHandlerImpl implements DecisionHandler { //用来判断当前操作执行哪个分支 @Override public String decide(OpenExecution execution) { int money = (Integer) execution.getVariable("报销金额"); //让总经理审批一下 if(money>1000){ return "to 总经理审批"; } //让流程结束 return "to end1"; } }
2、活动的(fork/join)
@Test public void test(){ URL url = this.getClass().getResource("test.jpdl.xml"); String deploymentID = processEngine.getRepositoryService()// .createDeployment()// .addResourceFromUrl(url)// .deploy(); System.out.println("部署流程定义成功!deploymentID"+deploymentID); ProcessInstance pi = processEngine.getExecutionService().startProcessInstanceByKey("test"); System.out.println("启动流程实例成功!id="+pi.getId()); }
3、个人任务
@Test public void testCompleteTask(){ // 4,执行完第1个任务,并使用指定的Transition离开 String taskId = "200001"; String transitionName1 = "to end1"; String transitionName2 = "to 审批 [总经理]"; // 办理完任务,使用指定名称的Transition离开 // processEngine.getTaskService().completeTask(task.getId(), transitionName2); //processEngine.getTaskService().completeTask(taskId, transitionName2); processEngine.getTaskService().completeTask(taskId); System.out.println("任务执行完毕!"); }
4.组任务
组任务及三种分配方式: 1:在.jpdl.xml中直接写 candidate-users=“小A,小B,小C,小D" 2:在.jpdl.xml中写 candidate-users =“#{userIds}”,变量的值要是String的。 使用流程变量指定办理人 Map<String, Object> variables = new HashMap<String, Object>(); variables.put("userIDs", "大大,小小,中中"); 3,使用AssignmentHandler接口,使用类实现该接口,在类中定义: //添加组任务的用户 assignable.addCandidateUser("张无忌"); assignable.addCandidateUser(“张三丰”); 组任务分配给个人任务: processEngine.getTaskService().takeTask(taskId, userId); 个人任务分配给组任务: processEngine.getTaskService().assignTask(taskId, null); 向组任务添加人员: processEngine.getTaskService().addTaskParticipatingUser(taskId, userId, Participation.CANDIDATE); 组任务对应的表: jbpm4_participation
事件
1:在根元素中,或在节点元素中,使用<on event=“”>元素指定事件,其中event属性代表事件的类型(start和end表示开始和结束)。 2:在<on>中用子元素<event-listener class="EventListenerImpl" />,指定处理的类,要求指定的类要实现EventListener接口 3:事件类型: (1):<on>元素放在根元素(<process>)中,可以指定event为start或end,表示流程的开始与结束。 (2):<on>元素放在节点元素中,可以指定event为start或end,表示节点的进入与离开 (3):在Start节点中只有end事件,在End节点中只有start事件。 (4):在<transition>元素中直接写<event-listener class=“”>,就是配置事件。(因为在这里只有一个事件,所以不用写on与类型) (5):在<task>元素中还可以配置assign事件,是在分配任务时触发的。
<process name="test" xmlns="http://jbpm.org/4.4/jpdl"> <!-- 在整个流程实例启动的时候进行事件监听 --> <on event="start"> <event-listener class="cn.itcast.jbpm.k_event.EventListenerImpl" /> </on> <!-- 在整个流程实例停止的时候进行事件监听 --> <on event="end"> <event-listener class="cn.itcast.jbpm.k_event.EventListenerImpl" /> </on> <start name="start1" g="113,78,48,48"> <!-- 在启动活动的时候进行事件监听 --> <on event="end"> <event-listener class="cn.itcast.jbpm.k_event.EventListenerImpl" /> </on> <transition name="to task1" to="发送短信" g="-53,-17"/> </start> <end name="end1" g="119,301,48,48"> <!-- 在结束活动的时候进行事件监听 --> <on event="start"> <event-listener class="cn.itcast.jbpm.k_event.EventListenerImpl" /> </on> </end> <task name="发送短信" g="97,189,92,52" assignee="张三"> <!-- 在任务启动的时候进行事件监听 --> <on event="start"> <event-listener class="cn.itcast.jbpm.k_event.EventListenerImpl" /> </on> <!-- 在任务退出的时候进行事件监听 --> <on event="end"> <event-listener class="cn.itcast.jbpm.k_event.EventListenerImpl" />
@SuppressWarnings("serial") public class EventListenerImpl implements EventListener { @Override public void notify(EventListenerExecution execution) throws Exception { System.out.println(“触发了事件监听,当前活动为:"+execution.getActivity()); } }
3.jbpm的具体过程实现
//获取工作流文件
URL url = this.getClass().getResource("test.jpd1.xml");
//部署流程定义
Stirng deploymentID = processEngine.getRepositoryService()
.createDeployment()
.addRosourceFromUrl(url)
.deploy();
System.out.println("部署ID:"+deploymentID);
//启动流程实例
ProcessInstance pi = processEngine.getExecutionService()
.startProcessInstanceByKey("test");
System.out.prinln("流程实例id"+pi.getId());
//查询我的任务列表
Task task = processEngine.getTaskService()
.createTaskQuery()
.processInstanceId(pi.getId())
.uniqueResult();//按照流程实例查询只有一个任务的结果对象
System.out.println("任务Id”+task.getId());
System.out.println("任务名称”+task.getName());
System.out.println("任务的办理人”+task.getAssignee());
System.out.println("任务办理时间”+task.getCreateTime());
//指定连线完成任务
String outcome = "流程执行的下一步(to end1)";
//完成任务
processEngine.getTaskService()
.completeTask(task.getId(),outcome);