工作流 jbpm(图文并茂)(下)

简介: 工作流 jbpm(图文并茂)

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

相关文章
|
12月前
|
存储 XML Java
Activiti7(图文并茂)
Activiti7(图文并茂)
|
存储 开发工具 数据库
搭建zotero到obsidian的工作流
所谓“工欲善其事,必先利其器”(差生文具多),想要针对一个领域研究出成果,首先需要建立其对于这个领域完善的知识体系,即形成属于自己的知识库。现在有非常多的笔记软件,例如Notion、语雀、Obsidian等等,对于建立知识库非常有帮助,下面我就来谈谈我个人探索出来的一套从zotero管理文献,到阅读文献做笔记再到obsidian中形成阅读笔记的丝滑工作流。
1727 0
|
15天前
|
API
工作流JBPM流程图说明
工作流JBPM流程图说明
18 0
|
15天前
|
XML 消息中间件 监控
工作流 jbpm概述
工作流 jbpm概述
16 0
|
15天前
|
XML 数据库 数据格式
工作流JBPM画图与配置
工作流JBPM画图与配置
16 0
|
9月前
|
XML Oracle Java
Flowable工作流入门看这篇就够了
Flowable工作流入门看这篇就够了
1319 0
|
12月前
|
XML 存储 Java
工作流 jbpm(图文并茂)
工作流 jbpm(图文并茂)
|
12月前
|
Oracle Java 关系型数据库
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!(2)
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!
|
12月前
|
XML 存储 供应链
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!(1)
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!
|
12月前
|
XML Java 数据库连接
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!(4)
史上最全 Activiti 学习教程,一文搞定最强工作流引擎!