4.4 流程操作与数表交互说明
发布一个流程deploy
① jbpm4_deployment(流程定义):新增一条记录,记录新增的流程名称、时间、状态;
② jbpm4_lob(存储表): 新增一条记录,保存根据流程定义xml形成的二进制数据(同时也保存变量variable);
③ jbpm4_deployprop(流程定义属性表):新增四条记录,记录流程的属性,在“KEY_”里面记录一下四项内容:
Langid 标识解析流程定义使用的 jpdl 的版本;
Pdid 流程定义的 id , 唯一标识一个流程;
Pdkey 流程的 key ,标识同一类流程;
Pdversion 标识流程的版本。
zip包:(包含png和jpdl.xml)后
① JBPM4_DEPLOYMENT;
② JBPM4_DEPLOYPROP ;
③ JBPM4_LOB多两条。
开始一个流程startProcessInstanceByKey后
① jbpm4_execution(流程实例表):新增一条记录
② jbpm4_hist_procinst(流程实例历史表):新增一条记录
③ jbpm4_variable (上下表):新增一条记录
④ jbpm4_task (任务表):新增一条记录
⑤ jbpm4_hist_task(任务历史表):新增一条记录
⑥ jbpm4_hist_actinst (活动节点实例表):新增一条记录
填写申请信息
① jbpm4_variable(上下表) : 新增N条记录,根据表单信息决定
② jbpm4_task (任务表):新增一条记录
③ jbpm4_hist_task(任务历史表):新增一条记录
④ jbpm4_hist_actinst (活动节点实例表):新增一条记录
审批申请信息
1.同意:
① jbpm4_hist_actinst (活动节点实例表):新增一条记录
2.驳回:
① jbpm4_task (任务表):新增一条记录
② jbpm4_hist_task(任务历史表):新增一条记录
③ jbpm4_hist_actinst (活动节点实例表):新增一条记录
审批结束
① jbpm4_hist_actinst (活动节点实例表):新增一条记录
5 相关概念
流程定义:Process definition
一个流程的步骤说明。如一个请假流程、报销流程、借款流程等。是一个规则。
流程实例:Process instance
代表流程定义的一次执行。如张三昨天按照请假流程请了一次假。一个流程实例包括了所有运行的阶段,其中最典型的属性就是跟踪当前节点的指针。
Execution 执行
一般情况下,一个流程实例是一个执行树的根节点。
使用树状结构的原因在于,这一概念只有一条执行路径,使用起来更简单。业务API不需要了解流程实例和执行之间功能的区别。因此,API里只有一个执行类型来引用流程实例和执行。
6 流程图说明
6.0 快速上手
如图:在工程根路径下新建一个"Source Folder"文件夹
在上一步新建的文件夹里新建文件,如下:
建好后,打开 如下图所示:
画个简单的 图:
上图简单的说明:
当上图的活动部署并启动(部署和启动下文再细说)后,活动先到达部门审批,此时,只有"小李"(画流程图时指定的部门审批人)能看见自己的任务列表有该任务,流程下一步的 "经理"在自己的任务列表里是看不见该任务的。
当"小李"办理了该任务后,该任务将不会在"小李"的任务列表显示,而此时"经理"的任务列表里就有了该任务了。
"小李"办理了该任务后,该流程结束,该任务将不会在任何人的任务列表显示。
6.1 活动Activity / 节点Node
我们所用到的 活动 都在上图中了,下面介绍经常用到的活动的含义:
6.1.1 start 开始活动
代表流程的开始边界,一个流程有且只能有一个 start 活动。开始活动只能指定一个 Transition 。在流程实例启动后,会自动的使用这个唯一的 Transition 离开开始活动,到下一个活动。
6.1.2 end 结束活动
代表流程的结束边界,可以有多个,也可以没有。如果有多个,则达到任一个结束活动,整个流程就都结束了;如果没有,则到达最后面那个没有 Transition 的活动,流程就结束了。
6.1.3 task 任务活动
等待补充
6.1.4 decision 判断活动
等待补充
6.1.5 fork/join 分支/聚合活动
这是多个分支并行(同时)执行的,并且所有的分支 Execution 都到 join 活动后才向后执行。
展现在图中就是:task2、task3 和 task4 这三个任务都执行完毕,流程才继续往 task5 走。task2、task3 和 task4 中任意一个没有完成,任务都不会往下走。
注意: fork 和 join 是配合在一起使用的。
6.2 流转 Transition / 连线 (单向箭头)
6.2.1 开始活动
开始活动中只能有一个 Transition 。
6.2.2 结束活动
结束活动中没有 Transition 。
6.2.3 其他活动
其他活动中都是可以有1个或者n个 Transition 。
7 画图与配置
7.1 画图
完成以上的配置和概念了解后,我们来画图实际操作吧:
首先,我们画出如下图这样的一个流程图出来:(下图彩线箭头和汉语文字为辅助添加的,不包含在原流程图中)
7.2 配置
7.2.1 配置任务办理人
7.2.1.1 写死的方式配置任务办理人(不推荐)
当我们点击流程图中的每个节点,流程图下方都会出现如下图示的 属性编辑 框。
如果没有弹出该框。请在myeclipse 工具 ,按下图操作:
弹出该框后,我们看到该框有两个编辑栏可编辑:
点击 General 属性,可以在 右侧 输入框 输入 该节点的名称 ,输入名称后 该名称将会作为 该节点的name显示在流程图中和保存在数据库的相关表中(如下图示)。
点击 Assignment 属性,可以在右侧 输入框 配置该节点的
我们将本案例的流程图的 task1 和 task2 的任务办理人按照同样的方式分别设置成 “张三” 和 “李四” 。
7.2.1.2 #{}方式配置任务办理人
如下图操作:
然后,这样设置的是一个动态的,我们在完成 该节点的上一步 的任务的时候去设置该处的具体任务办理人。
具体代码在办理任务的时候添加。
7.2.1.3 实现接口方式配置任务办理人
该方式不需要在画图处设置,但是要在 流程图 的 xml 文件里设置。
我们此处是要设置 task4 的办理人,所以我们打开 流程图 的Source文件(如上图示):
找到 task4 的节点 ,加入如下节点,在该节点指定该处任务办理人的处理类的全路径名(完成后效果如下)。
<task name="task4" g="512,360,92,52"> <assignment-handler class="com.snow.config.User3AssignmentHandlerImpl"> </assignment-handler> <transition name="to join1" to="join1" g="-49,-22"/> </task>
注意:该类必须是实现了 AssignmentHandler 接口的类(如下)。
public class User3AssignmentHandlerImpl implements AssignmentHandler { private static final long serialVersionUID = 1L; @Override public void assign(Assignable assignable, OpenExecution execution) throws Exception { // 模拟从 数据库 拿到 的 相关人 String userName = "王五"; // 将 获取到的办理人 设置 给 该任务 assignable.setAssignee(userName); } }
该类的调用时机是在 流程图 的流走到该节点自动调用。
7.2.1.4 方法指定方式分配任务办理人
此方式不需要在流程图中指定。需要在流程走到该节点之前的任何时机指定。
代码如下:
// 使用默认配置文件,先获取流程引擎 ProcessEngine processEngine = Configuration.getProcessEngine(); // 获取任务serviec TaskService taskService = processEngine.getTaskService(); String tasjId = "1010101"; String userId = "赵六"; askService.assignTask(taskId, userId);
7.2.2 配置节点属性
7.2.2.1 判断节点(decision)
这是一个判断节点,流程走到这一步会根据该流程的特定属性进行判断,判断条件写在一个实现了 DecisionHandler 接口的类里,并在这里指定类的全限定类名。
实现类如下:
public class My3DecisionHandlerImpl implements DecisionHandler { private static final long serialVersionUID = 2L; // 根据指定的属性进行流程下一步的判断 @Override public String decide(OpenExecution execution) { // 获取申请数额 (这里的属性是在 流程到达该节点前指定的) Double money = Double.parseDouble((String) execution.getVariable("money")); // 重新分配流程下一步走向 if(money > 100000){ // task6 节点名称 具体在画图时已指定 return "to task6"; } // end1 介绍节点名称 具体在画图时已指定 return "to end1"; } }
该类控制下图的走向:
7.2.2.2 分支/聚合节点
如上图示:
流程完成 task2 后,会进入 fork(分支) 节点,流程一分为二:指向 task3 和 task4 。此时 task3 和 task4 节点任务办理人分别在他们的任务列表会看到该任务,只有当他们完成了各自的任务后,该流程才能继续往下走(task3 和 task4 任何一个节点任务没有完成,流程都不会再继续往下走),汇入 join 节点。
注意:区别于decision判断节点,分支与聚合节点本身是不需要额外的代码控制的,这两个节点本身自带的逻辑控制功能。
7.3 完成画图与配置后的效果
7.3.1 完成后的图
至此,我们的流程图 层面的配置就完了,流程图如下:
7.3.2 完成后配置的xml文件
流程图产生的xml文件如下(注意看配置相关节点节后与原xml文件的对比):
<?xml version="1.0" encoding="UTF-8"?><process name="test" xmlns="http://jbpm.org/4.4/jpdl"> <start g="472,32,48,48" name="start1"> <transition g="-46,-17" name="to task1" to="task1"/> </start> <task assignee="张三" g="450,112,92,52" name="task1"> <transition g="-47,-10" name="to task2" to="task2"/> </task> <decision g="472,608,48,48" name="exclusive1"> <handler class="com.snow.config.My3DecisionHandlerImpl" /> <transition g="6,-19" name="to end1" to="end1"/> <transition g="-45,-17" name="to task6" to="task6"/> </decision> <task assignee="李四" g="450,196,92,52" name="task2"> <transition g="-44,-8" name="to fork1" to="fork1"/> </task> <task assignee="#{user3}" g="388,360,92,52" name="task3"> <transition g="-49,-22" name="to join1" to="join1"/> </task> <task g="512,360,92,52" name="task4"> <assignment-handler class="com.snow.config.User3AssignmentHandlerImpl"/> <transition g="-49,-22" name="to join1" to="join1"/> </task> <fork g="472,280,48,48" name="fork1"> <transition g="-44,-15" name="to task3" to="task3"/> <transition g="4,-10" name="to task4" to="task4"/> </fork> <join g="472,444,48,48" name="join1"> <transition g="-52,-22" name="to task5" to="task5"/> </join> <task g="450,524,92,52" name="task5"> <transition g="-79,-22" name="to exclusive1" to="exclusive1"/> </task> <end g="472,772,48,48" name="end1"/> <task g="378,688,92,52" name="task6"> <transition g="-50,-22" name="to end1" to="end1"/> </task></process>
8 操作API
8.1 部署流程
官方提供了2种方式的部署。
8.1.1 部署方式1-源文件
这种部署方式需要将 流程图文件 放在如下路径中(process文件与src文件同类型属于Source Folder),这样通过如下方式1部署时不会出现路径问题。
部署代码:
//部署方式1 @Test void deploy1(){ //使用默认配置文件,获取流程引擎 ProcessEngine processEngine = Configuration.getProcessEngine(); String deployId = processEngine.getRepositoryService() .createDeployment() .addResourceFromClasspath("aaa.jpdl.xml") .addResourceFromClasspath("aaa.png") .deploy(); System.out.println("部署方式1 : deployId:" + deployId); }
执行上面的代码后,控制台打印如下:
此时数据库表有如下变化:
数据定义表(jbpm4_deployment ) 多了一个字段 :id为 1500001 的流程定义,如下图示。
数据定义属性表(jbpm4_deployprop)也有变化,具体自己部署查看下。
8.1.2 部署方式2-zip包
以.zip压缩包的方式部署,我们将 画图产生的两个文件 打包成 .zip压缩包文件,放在如下图示的位置。
该种方式部署代码如下:
// 部署方式2 ZIP压缩文件 @Test public void deploy2(){ ProcessEngine processEngine = Configuration.getProcessEngine(); InputStream in = this.getClass().getClassLoader().getResourceAsStream("test.zip"); ZipInputStream zipInputStream = new ZipInputStream(in); // 部署 String deployId = processEngine.getRepositoryService() .createDeployment() .addResourcesFromZipInputStream(zipInputStream) .deploy(); System.out.println("部署方式2 : deployId:" + deployId); }
执行完上面部署代码后,控制台打印如下:
部署方式2 : deployId:1510001
注意:
就我们的demo而言:部署方式1 和 部署方式2 此时部署的其实是同一个流程,只是部署方式不一样。
所以其实是将同一个流程部署了两次。表现在数据库表中就是有两个版本的流程部署了。
版本号在第一次部署默认为1,后面部署相同的流程版本号会自动+1。
数据定义属性表(jbpm4_deployprop)数据:
8.2 查询流程实例
部署后就能查到流程定义。
8.2.1 查询所有
查询所有已经部署的流程定义,代码如下(会查询所有已经部署的流程定义,多版本也会一起返回)
//查询所有流程定义 @Test public void findAll(){ List<ProcessDefinition> list = processEngine.getRepositoryService() .createProcessDefinitionQuery() .orderAsc(ProcessDefinitionQuery.PROPERTY_KEY) .list(); // 展示数据 List<Map<String, String>> resultList = new ArrayList<Map<String,String>>(); for(ProcessDefinition d : list){ Map<String, String> map = new HashMap<>(); map.put("id",d.getId()); map.put("name",d.getName()); map.put("key",d.getKey()); map.put("version",String.valueOf(d.getVersion())); map.put("deploymentId",d.getDeploymentId()); resultList.add(map); } System.out.println(resultList); }
执行上面的查询代码马,控制台打印如下:
[{deploymentId=760001, name=applyFor, id=applyFor-1, version=1, key=applyFor}, {deploymentId=1440015, name=groupTest1125, id=groupTest1125-1, version=1, key=groupTest1125}, {deploymentId=1350008, name=leave, id=leave-1, version=1, key=leave}, {deploymentId=1500001, name=test, id=test-1, version=1, key=test}, {deploymentId=1510001, name=test, id=test-2, version=2, key=test}, {deploymentId=990001, name=test11220846, id=test11220846-1, version=1, key=test11220846}, {deploymentId=980009, name=testGroup2, id=testGroup2-1, version=1, key=testGroup2}]
8.2.2 查询所有最新版本的流程定义
会查询出每个Key下的最新版本,后面我们的启动就是按照指定key下的最新版本启动的
// 查询所有最新版本的流程定义 @Test public void findAllLastVersion(){ List<ProcessDefinition> list = processEngine.getRepositoryService() .createProcessDefinitionQuery() .orderAsc(ProcessDefinitionQuery.PROPERTY_VERSION) .list(); // 过滤 过滤出最新版本 Map<String, ProcessDefinition> mapBefore = new HashMap<String, ProcessDefinition>(); for(ProcessDefinition definition : list){ mapBefore.put(definition.getKey(),definition); } // 展示数据 List<Map<String, String>> resultList = new ArrayList<Map<String,String>>(); for(ProcessDefinition d : mapBefore.values()){ Map<String, String> map = new HashMap<>(); map.put("id",d.getId()); map.put("name",d.getName()); map.put("key",d.getKey()); map.put("version",String.valueOf(d.getVersion())); map.put("deploymentId",d.getDeploymentId()); resultList.add(map); } System.out.println(resultList); }
执行上面的查询代码后,控制台打印如下:
[{deploymentId=990001, name=test11220846, id=test11220846-1, version=1, key=test11220846}, {deploymentId=1510001, name=test, id=test-2, version=2, key=test}, {deploymentId=980009, name=testGroup2, id=testGroup2-1, version=1, key=testGroup2}, {deploymentId=1350008, name=leave, id=leave-1, version=1, key=leave}, {deploymentId=1440015, name=groupTest1125, id=groupTest1125-1, version=1, key=groupTest1125}, {deploymentId=760001, name=applyFor, id=applyFor-1, version=1, key=applyFor}]
注意与查询所有的结果比较:key 为 test 的结果只有一条了,且version=2。
8.3 删除流程定义
删除流程定义可以按照id和key删除。
8.3.1 按照id删除(有关联信息会抛异常)
// 删除流程定义 @Test public void deleteById(){ String deploymentId = "1500001"; ProcessEngine processEngine = Configuration.getProcessEngine(); // 有关联信息,抛异常 processEngine.getRepositoryService().deleteDeployment(deploymentId); }
上述这种删除方法,如果该流程id对应的流程有关联信息,将会抛异常。
8.3.2 按照id删除(会删除关联信息)
// 删除流程定义 @Test public void deleteById(){ String deploymentId = "1500001"; ProcessEngine processEngine = Configuration.getProcessEngine(); // 有关联信息,会级联删除 processEngine.getRepositoryService().deleteDeploymentCascade(deploymentId); }
上述这种删除方法,如果该流程id对应的流程有关联信息,会级联删除!
8.3.3 按照key删除
// 删除流程定义 按照key @Test public void deleteByKey(){ String key = "b"; List<ProcessDefinition> list = processEngine.getRepositoryService() .createProcessDefinitionQuery() .processDefinitionKey(key) .list(); // 遍历 删除 if( list != null && list.size() > 0){ for(ProcessDefinition processDefinition : list){ System.out.println(processDefinition.getId()); ProcessEngine processEngine = Configuration.getProcessEngine(); processEngine.getRepositoryService(). deleteDeploymentCascade(processDefinition.getDeploymentId()); } } }
该方式会将该key下的所有实例删除。
8.4 获取部署时的文件资源
8.4.1 获取部署时的文件资源方式1
该方式要指定jbpm4_deployment表 DBID 和 jbpm4_lob 表中deplotmentId对应的name_的值
// 获取部署时的文件资源(查看流程图)
@Test public void get() throws Exception{ ProcessEngine processEngine = Configuration.getProcessEngine(); // jbpm4_deployment表 DBID String deplotmentId = "1510001"; // jbpm4_lob 表中deplotmentId对应的name_的值 String resourceName = "test.png"; // 获取所有资源名称 Set<String> names = processEngine.getRepositoryService().getResourceNames(deplotmentId); for(String name : names){ System.out.println(name); } InputStream in = processEngine.getRepositoryService().getResourceAsStream(deplotmentId, resourceName); // 输出到本地文件 (路径自己指定,但要注意路径中包含的文件夹都存在) OutputStream outputStream = new FileOutputStream("d:/photoAlbum/process-" + deplotmentId +".png"); for(int b = -1;(b = in.read()) != -1;){ outputStream.write(b); } in.close(); outputStream.close(); }
执行上述代码,会在我们指定的路径下得到如下图片:就是我们部署时候的流程图。
8.4.2 获取部署时的文件资源方式2
该方式要指定 jbpm4_execution 表中的 PROCDEFID 字段。
@Test // 得到图片资源2 public void get2() throws IOException{ // jbpm4_execution 表中的 PROCDEFID String processDefinitionId = "test-2"; ProcessDefinition processDefinition = processEngine.getRepositoryService() .createProcessDefinitionQuery() .processDefinitionId(processDefinitionId) .uniqueResult(); InputStream in = processEngine.getRepositoryService().getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getImageResourceName()); // 输出到本地文件 OutputStream outputStream = new FileOutputStream("d:/photoAlbum/process/deplotmentImg/" + processDefinitionId + ".png"); for(int b = -1;(b = in.read()) != -1;){ outputStream.write(b); } in.close(); outputStream.close(); }
执行上述代码,会在我们指定的路径下得到如下图片:就是我们部署时候的流程图。
8.5 启动实例
8.5.1 按照key启动(不加参数)
@Test // 启动 -- 简单的启动 public void startProcessInstace(){ ProcessEngine processEngine = Configuration.getProcessEngine(); // 会启动该key下的最新版本的流程 ProcessInstance instance = processEngine.getExecutionService().startProcessInstanceByKey("test"); System.out.println(instance.getId()); System.out.println(instance.getName()); System.out.println(instance.getIsProcessInstance()); System.out.println(instance.getKey()); System.out.println(instance.getState()); }
注意:这里出现了 key 的概念。回顾我们在上一步画流程图的时候,并没有指定key,但是 我们在创建流程图的时候对文件进行了命名,如果不指定key,那么默认的key就和name同名。
执行上面的启动代码后,控制台打印如下:
8.5.2 按照key启动(加入参数)
// 启动 -- 并加入一些参数 @Test public void startProcessInstance(){ String processKey = "test"; Map<String, String> variableMap = new HashMap<String, String>(); String username = "JackMa";// 申请人 这里的数据是从服务器过去当前登录人 variableMap.put("申请人", username); // 实际数据从表单获取 variableMap.put("申请事由", "扩展东南亚业务"); variableMap.put("申请金额", String.valueOf(200000));// 前端填写必须是数字,后台转String // 将date转换为字符串 variableMap.put("申请时间", DateUtil.convertDate2String(new Date(), null)); variableMap.put("备注", "XXX"); variableMap.put("最新进度",username+"-提交了申请"); variableMap.put("状态", "进行中..."); ProcessEngine processEngine = Configuration.getProcessEngine(); ProcessInstance instance = processEngine.getExecutionService().startProcessInstanceByKey(processKey, variableMap); System.out.println(instance.getId()); }
执行启动代码,控制台打印如下:
此时 数据库中 jbpm4_variable 表就会有以下数据:
8.5.3 启动流程实例的说明
API也提供了按照id的启动方式,但是在实际业务中用不到。(因为不会去启动一个作废的审批流程)
8.6 查询任务
8.6.1 查询所有未办理任务
// 查询所有未办理的任务列表 @Test public void getAllTask(){ List<Task> list = processEngine.getTaskService() .findPersonalTasks(null); for(Task task : list){ System.out.println("id="+task.getId() + ",name=" + task.getName() + ",assignee="+task.getAssignee() + ",createTime="+task.getCreateTime()); } }
上述方法会查询出所有未办理的任务:
8.6.2 查询个人未办理任务
// 查询我的未办理的任务列表 @Test public void getTaskByName(){ String userName = "张三"; List<Task> list = processEngine.getTaskService().findPersonalTasks(userName); for(Task task : list){ System.out.println("id="+task.getId() + ",name="+task.getName() + ",assignee="+task.getAssignee() + ",createTime="+task.getCreateTime()); System.out.println(task.getExecutionId()); } }
查询结果:
可以看出:张三 这个用户有两条未办理的任务。其中executionId去掉 " key." 就会得到 一个新的字段。
例如:executionId=test.1530001 ----> 153001 会对应到 jbpm4_variable 表中的 EXECUTION 字段 , 通过该字段又能得到该表下的参数信息 (该参数信息是在启动实例的时候指定的,后续该数据将会是从前台申请表单拿到,并在启动时加入)。
8.6.3 查询个人的待办组任务
目前为止我们还没有指定组任务(组任务在 8.10),所以该处查询暂时会是空。
// 找到个人 的 分组 任务 @Test public void findGroupTasksByUser(){ String user = "小明"; List<Task> tasks = processEngine.getTaskService() .createTaskQuery() .candidate(user) .list(); System.out.println(tasks.size()); for(Task task : tasks){ System.out.println(task.getId() + task.getName() + task.getAssignee()); } }
8.7 办理任务
8.7.1 办理个人任务
办理前数据表中:
办理任务:
// 办理个人任务 @Test public void comPeletePersonTask111(){ String taskId = "1520002"; String user = "张三"; List<Task> list = processEngine.getTaskService().findPersonalTasks(user); System.out.println(list.size()); if( list == null || list.size() < 1){ // throw ... System.out.println("该用户当前没有可以办理的任务!"); return; } for(Task task : list){ if(user.equals(task.getAssignee()) && taskId.equals(taskId)){ // 办理任务 processEngine.getTaskService().completeTask(taskId); break; } } }
办理后数据表:
8.7.2 办理个人组任务
个人组任务:组任务节点的办理人不是一个人,而是一组拥有相同权限的人(设置组任务办理人在8.10.1)。
组任务不能直接办理,需要先将该组任务 拾取 到个人任务中。这样该组任务就变成了个人任务,此时办理方法同8.7.1。
拾取任务:
@Test public void ban(){ String taskId = "1470004"; String user = "小红"; // 拾取前 判断下 该组任务的办理用户中是否有 该用户 // 判断 略... processEngine.getTaskService().takeTask(taskId, user); } // 拾取任务后 该组任务就变为自己的任务了 办理 同 8.7.1 // 办理 略...
8.8 驳回任务
// 驳回申请 @Test public void jujue(){ String taskId = "410001"; Task task = processEngine.getTaskService().getTask(taskId); System.out.println(task.getExecutionId()); // 在驳回任务前最好先做个判断,只能驳回属于自己的任务 // 判断 略... processEngine.getExecutionService() .endProcessInstance(task.getExecutionId(),ProcessInstance.STATE_ENDED); }
8.9 流程变量
流程变量设置的值的作用域是整个流程(流程启动到流程结束,流程变量在流程结束后会自动从数据库表删除)。
流程变量 会保存在 jbpm4_variable 表中。
8.9.2 设置流程变量
// 设置流程变量 @Test public void testSetVariables(){ String executionId = ""; String taskId = ""; String name = ""; Object value = ""; Map<String, Object> variableMap = new HashMap<String, Object>(); String processDefinitionKey = ""; // 以下 设置 流程变量的方式 任选其一就行 // 根据 Execution 设置一个流程变量 processEngine.getExecutionService().setVariable(executionId, name, value); // 根据 Execution 设置多个流程变量 processEngine.getExecutionService().setVariables(executionId, variableMap); // 根据 Task 设置多个流程变量(放入map) processEngine.getTaskService().setVariables(taskId, variableMap); // 启动时候 加入流程变量 processEngine.getExecutionService().startProcessInstanceByKey(processDefinitionKey, variableMap); // 办理指定任务 并 加入 参数 processEngine.getTaskService().completeTask(taskId, variableMap); }
8.9.3 获取流程变量
// 获取流程变量 @Test public void testGetVariables(){ String executionId = ""; String taskId = ""; String variableName = ""; // 根据 Execution获取指定名称的一个流程变量 processEngine.getExecutionService().getVariable(executionId, variableName); // 根据 Execution获取所有流程变量 processEngine.getExecutionService().getVariableNames(executionId); // 根据 Execution获取指定名称的所有流程变量 Set<String> variableNames1 = null; processEngine.getExecutionService().getVariables(executionId, variableNames1); // 同上 processEngine.getTaskService().getVariable(taskId, variableName); processEngine.getTaskService().getVariableNames(taskId); Set<String> variableNames2 = null; processEngine.getTaskService().getVariables(taskId, variableNames2); }
所有的流程变量 都在 jbpm4_variable 表中可以查看。
8.10 组任务
8.10.1 组任务的分配
8.10.1.1 写死的方式指定
该方式不推荐
人名与人名之间用 英文逗号 隔开。
8.10.1.2 实现AssignmentHandler接口指定
在.xml文件配置如下:
<task name="组任务2" g="347,280,92,52"> <assignment-handler class="com.snow.config.Group11AssignmentHandler"> </assignment-handler> <transition name="to end1" to="end1" g="-50,-22"/> </task>
类实现:
public class Group11AssignmentHandler implements AssignmentHandler { private static final long serialVersionUID = 11L; @Override public void assign(Assignable assignable, OpenExecution execution) throws Exception { // 获取 该分组任务的 候选人 ooo_task2_users流程变量是在流程走到该节点前指定的 String vairableName = "ooo_task2_users"; String[] users = (String[]) execution.getVariable(vairableName); // 将 人员 分配 给 组任务 for(String user : users){ assignable.addCandidateUser(user); } } }
8.10.2 查询自己的组任务
// 查询自己的组任务 @Test public void findGroupTasksByUser(){ String user = "小明"; List<Task> tasks = processEngine.getTaskService() .createTaskQuery() .candidate(user) .list(); System.out.println(tasks.size()); for(Task task : tasks){ System.out.println(task.getId() + task.getName() + task.getAssignee()); } }
8.10.3 办理自己的组任务
同 8.7.2
getExecutionService().getVariables(executionId, variableNames1); // 同上 processEngine.getTaskService().getVariable(taskId, variableName); processEngine.getTaskService().getVariableNames(taskId); Set<String> variableNames2 = null; processEngine.getTaskService().getVariables(taskId, variableNames2); }
所有的流程变量 都在 jbpm4_variable 表中可以查看。
8.10 组任务
8.10.1 组任务的分配
8.10.1.1 写死的方式指定
该方式不推荐
人名与人名之间用 英文逗号 隔开。
8.10.1.2 实现AssignmentHandler接口指定
在.xml文件配置如下:
<task name="组任务2" g="347,280,92,52"> <assignment-handler class="com.snow.config.Group11AssignmentHandler"> </assignment-handler> <transition name="to end1" to="end1" g="-50,-22"/> </task>
类实现:
public class Group11AssignmentHandler implements AssignmentHandler { private static final long serialVersionUID = 11L; @Override public void assign(Assignable assignable, OpenExecution execution) throws Exception { // 获取 该分组任务的 候选人 ooo_task2_users流程变量是在流程走到该节点前指定的 String vairableName = "ooo_task2_users"; String[] users = (String[]) execution.getVariable(vairableName); // 将 人员 分配 给 组任务 for(String user : users){ assignable.addCandidateUser(user); } } }
8.10.2 查询自己的组任务
// 查询自己的组任务 @Test public void findGroupTasksByUser(){ String user = "小明"; List<Task> tasks = processEngine.getTaskService() .createTaskQuery() .candidate(user) .list(); System.out.println(tasks.size()); for(Task task : tasks){ System.out.println(task.getId() + task.getName() + task.getAssignee()); } }
8.10.3 办理自己的组任务
同 8.7.2