jbpm会签的实现

一、会签的概念

1.1什么是会签

  即共同协商或审批。会签,又称会审,也就是流程中某个业务需要经过多人表决,并且根据表决意见的汇总结果,匹配设定的规则,决定流程的走向

1.2会签有多种类型

  1.多人只发表意见,并决策;2.部分人决策、部分只发现意见;3.如有决策,决策规则有以下几类:i:一票通过;ii:一票否决;iii:计同意票数;iv:计同意票数占比等。

二、典型会签实现逻辑

2.1参与会签人均需发表意见,全部审批后进入下一节点;

2.2参与会签人可以进行同意不同意的决策 ,全部进行决策后进入下一节点由下一节点审批人人工统计票数决定会签是否通过

三、会签实现方案

  jbpm并未直接提供会签机制,通过查阅资料以及前期对子任务及决策节点的理解,我们提出了一种基于子任务和决策的会签实现方案。

  会签设置表结构如下:

  流程定义如下:

<process xmlns=‘http://jbpm.org/4.4/jpdl‘>
  <start name=‘start1‘ g=‘195,109,48,48‘>
    <transition name=‘进入会签‘ g=‘-25,-15‘ to=‘会签节点‘/>
  </start>
  <task g=‘351.0909118652344,106.30681991577148,90,50‘ name=‘会签节点‘>
    <transition name=‘进入决策‘ g=‘-27,-11‘ to=‘decision 1‘/>
  </task>
  <decision g=‘536.0909118652344,106.30681991577148,48,48‘ name=‘decision 1‘>
    <transition name=‘决策路径1‘ g=‘-61,-19‘ to=‘end 1‘/>
    <transition name=‘决策路径2‘ g=‘-47,45‘ to=‘其他节点‘/>
  </decision>
  <end g=‘687.0909118652344,44.306819915771484,48,48‘ name=‘end 1‘/>
  <task g=‘677.0909118652344,163.30681991577148,90,50‘ name=‘其他节点‘>
    <transition name=‘正常结束‘ g=‘-26,-21‘ to=‘end 2‘/>
  </task>
  <end g=‘840.0909118652344,163.30681991577148,48,48‘ name=‘end 2‘/>
</process>

  流程图如下:

  

  如果工作流不是每一步关联不同表单,而采用同一表单根据步骤名称确定权限的话,需要特别注意子任务的任务名生成方法。子任务名而不是activityName将用作权限的确定。

if(!CollectionUtils.isEmpty(userIds) && !userIds.contains(null)) {
	if(userIds.size() > 1){
		String deploymentId = processDefineService.queryById(startFlowRunTime.getProcessDefineId()).getDeploymentId();
        if(StringUtils.isNotEmpty(task.getId())){
        	deploymentId = jbpmOperatorService.getProcessDefinitionByTaskId(task.getId()).getDeploymentId();
        }
        UserAssignEntity userAssign = userAssignService.queryUserAssignById(deploymentId, task.getActivityName(), UserAssignConstants.USERASSIGN_FLAG_ASSIGNEE,"");
	AssignsettingEntity assignsetting = new AssignsettingEntity();
	assignsetting.setDeployId(deploymentId);
	assignsetting.setActivityName(task.getActivityName());
    List<AssignsettingEntity> assignsettingList = assignsettingService.queryAssignsettingList(assignsetting);
    //处理会签
	if(userAssign != null && "1".equals(userAssign.getIsSigned()) ){
		if(CollectionUtils.isEmpty(assignsettingList)){
			jbpmOperatorService.createSubTask(task.getId(), userIds.toArray(new String[userIds.size()]));
		}else {
			//如需要通过子任务名确定表单权限
			try{
				jbpmOperatorService.createAssignSubTask(task.getId(), assignsettingList);
				}catch (Exception e) {
					throw new ProcessActivityException(e.getMessage());
				}
		}
	}else {
		//处理抢办
		for(String userId : userIds){
			jbpmOperatorService.addTaskParticipatingUser(task.getId(),userId);
		}
	}
}

  上面提到如需要通过会签子任务名确定表单权限,需特别注意createAssignSubTask方法:

/**
	 * 
	 * create sub task as assign task
	 * @author chao.gao
	 * @date 2015-2-10 上午10:09:58
	 * @see com.gaochao.oa.module.bpm.workflow.api.server.service.IJbpmOperatorService#createAssignSubTask(java.lang.String, java.util.List)
	 * @param id
	 * @param assignsettingList
	 * @throws Exception 
	 */
	@Override
	public void createAssignSubTask(String parentTaskId, List<AssignsettingEntity> assignsettingList) throws Exception{
	TaskServiceImpl taskServiceImpl = (TaskServiceImpl)processEngine.getTaskService();

		Task parentTask = taskServiceImpl.getTask(parentTaskId);

		Map<String,Object> vars = new HashMap<String,Object>();

		taskServiceImpl.setVariables(parentTaskId, vars);

		for(AssignsettingEntity assignsetting : assignsettingList){
			TaskImpl task = (TaskImpl)taskServiceImpl.newTask(parentTaskId);
			task.setAssignee(assignsetting.getUserId());
			task.setName(parentTask.getName() + "-" + assignsetting.getTaskName());
			task.setActivityName(parentTask.getName());
			task.setProcessInstance(getTaskById(parentTaskId).getExecution());
			task.setDescription(parentTask.getDescription());
			taskServiceImpl.saveTask(task);
		}
	}

  在jbpm4_task表中生成的子任务列表如下,其中子任务通过SUPERTASK_字段与父任务关联起来:

  

  子任务的办理:在办理子任务时首先获得其父任务的子任务列表,判断列表长度,如长度大于1,则只需要关闭本子任务;如子任务列表长度=1,说明目前仅有本子任务未办理,则将本任务及父任务同时关闭。

/**
	 * 处理父子任务,会签任务,完成任务
	 * @author chao.gao
	 * @date 2014-4-3 下午2:55:57
	 * @param parentTask
	 * @param subTask
	 * @param signalName
	 * @param variables
	 * @param opinion
	 */
	private void acch(TaskImpl parentTask, TaskImpl subTask, String signalName, Map<String,Object> variables, String opinion) {
		int subTasksSize = parentTask.getSubTasks().size();

		jbpmOperatorService.evict(subTask);
		jbpmOperatorService.evict(parentTask);
		if(subTasksSize > 1){//如当前父任务的子任务列表大于1,直接完成任务审批
			jbpmOperatorService.completeTask(subTask.getId());
		}else{
			jbpmOperatorService.completeTask(subTask.getId());//先完成子任务
			jbpmOperatorService.completeTask(parentTask.getId());//关闭父任务
			//更新父任务状态
			ProcessTaskEntity pT = processTaskService.queryByTaskId(parentTask.getId());//更新父任务状态
			if(pT != null){
				pT.setStatus("1");
			}
			processTaskService.update(pT);
		}
	}

  会签是否通过的决策:

	/** 
	 * 流程决策
	 * @author chao.gao
	 * @date 2014-2-13 上午10:01:36
	 * @see org.jbpm.api.jpdl.DecisionHandler#decide(org.jbpm.api.model.OpenExecution)
	 * @param arg0
	 * @return
	 */
	@Override
	public String decide(OpenExecution openExecution) {

		ProcessEngine processEngine = (ProcessEngine) SpringContextUtil.getApplicationContext().getBean("processEngine");

		IDecisionRuleService decisionRuleService= (IDecisionRuleService)SpringContextUtil.getApplicationContext().getBean("decisionRuleService");

		String processDefinitionId = openExecution.getProcessDefinitionId();
		ProcessDefinition processDefinition = processEngine.getRepositoryService()
				.createProcessDefinitionQuery()
				.processDefinitionId(processDefinitionId)
				.uniqueResult();

		String deploymentId = processDefinition.getDeploymentId();

		Activity curActivity = openExecution.getActivity();
		DecisionRuleEntity decisionRule = decisionRuleService.queryByDeployIdAndActivityName(deploymentId, curActivity.getName());
		if(decisionRule!=null){
			Interpreter it = new Interpreter();
			try{
				Map<String, ?> vars = openExecution.getVariables();
				Iterator<?> iterator = vars.entrySet().iterator();
				while (iterator.hasNext()) {
					Map.Entry entry = (Entry) iterator.next();
					String key = (String)entry.getKey();
					Object val = entry.getValue();
					it.set(key.replace(".", "_"), val);
				}
				 it.set("execution", openExecution);
				 it.eval(decisionRule.getRuleExpression().replace("‘", ""));
				 String tran = (String)it.get("tranTo");
				 return tran;
			}catch (Exception e) {
				//e.printStackTrace();
				throw new DecisionRuleException("条件判断表达式错误");
			}
		        
		}

		 String defaultTran = "";
		 List outs = curActivity.getOutgoingTransitions();
		 if (outs.size() > 0) {
			 defaultTran = ((Transition)outs.get(0)).getName();
		 }
		 return defaultTran;
	}

  通过以上逻辑,我们可以得到类似会签的效果,另外通过分配子任务方法我们也可以方便的进行加签(生成子任务)、减签(销毁子任务)。

四、其他会签方案

4.1 fork-join

  流程图如下:

  流程定义:

<process xmlns=‘http://jbpm.org/4.4/jpdl‘>
  <start name=‘start1‘ g=‘250,100,48,48‘>
    <transition name=‘进行会签‘ g=‘-28,-8‘ to=‘fork 1‘/>
  </start>
  <fork g=‘384.0909118652344,103.30681991577148,48,48‘ name=‘fork 1‘>
    <transition name=‘会签分支1‘ g=‘-68,-14‘ to=‘task 1‘/>
    <transition name=‘会签分支2‘ g=‘-67,31‘ to=‘task 2‘/>
  </fork>
  <task g=‘486.0909118652344,35.306819915771484,90,50‘ name=‘task 1‘>
    <transition name=‘会签汇聚1‘ to=‘join 1‘/>
  </task>
  <task g=‘494.0909118652344,169.30681991577148,90,50‘ name=‘task 2‘>
    <transition name=‘会签汇聚1‘ g=‘5,34‘ to=‘join 1‘/>
  </task>
  <join g=‘635.0909118652344,96.30681991577148,48,48‘ name=‘join 1‘>
    <transition name=‘会签结束‘ g=‘-27,-16‘ to=‘end 1‘/>
  </join>
  <end g=‘771.0909118652344,96.30681991577148,48,48‘ name=‘end 1‘/>
</process>

  fork-join的join节点具有multiplicity属性,通过该属性标记是全部task完成\仅有一个task完成进入join,或者是几个task完成才进入join,这也是fork-join可以用来实现会签的原因。

4.2 for-each(动态分支)

  流程图:

流程定义:

<process xmlns=‘http://jbpm.org/4.4/jpdl‘>
  <start name=‘start1‘ g=‘250,100,48,48‘>
    <transition name=‘进入会签‘ g=‘-26,-18‘ to=‘foreach 1‘/>
  </start>
  <foreach g=‘357.0909118652344,99.30681991577148,48,48‘ name=‘foreach 1‘>
    <transition name=‘进入会签任务‘ g=‘-39,-17‘ to=‘会签任务‘/>
  </foreach>
  <task g=‘512.0909118652344,98.30681991577148,90,50‘ name=‘会签任务‘>
    <transition name=‘会签决策‘ g=‘-23,-13‘ to=‘join 1‘/>
  </task>
  <join g=‘680.0909118652344,97.30681991577148,48,48‘ name=‘join 1‘>
    <transition name=‘结束‘ g=‘-18,-17‘ to=‘end 1‘/>
  </join>
  <end g=‘798.0909118652344,98.30681991577148,48,48‘ name=‘end 1‘/>
</process>

  foreach(动态分支)属于jbpm的高级应用,其能够实现会签的原理与fork-join相近,fork-join是fork之后生成多个分支,不同分支各是不同节点,最多分支量是提前确定的;而foreach则是通过设置其in\var等属性动态生成分支,其最多分支量可以进行设置。分支生成以后的会签工作与fork-join类似。

4.3 custom节点

  custom也是jbpm的高级应用,这里有一个详细的例子介绍通过custom实现会签。通过custom即定制化,我们可以任意定制custom的属性、逻辑、规则,所以通过custom是较自由、但也较复杂的会签实现方案。通过会签的custom实现,我们其实也可以发现,custom就是jbpm提供给我们的扩展接口,不仅会签,其他的工作流动作也可以通过定制实现。

  我们看一下其定义:

<custom class="sofocus.bpm.countersign.CountersignActivity" g="259,218,92,52"  
          name="领导会签">  
    <property name="description">  
      <string value="#{equipment}设备订购会签" />  
    </property>  
    <property name="form">  
      <string   
        value="/buyEquipment.do?action=countersign&amp;taskId=:{TASK_ID}" />  
    </property>  
    <property name="strategy">  
      <object class="sofocus.bpm.countersign.AllAgreeStrategy" />  
    </property>  
    <property name="passTransiton">  
      <string value="" />  
    </property>  
    <property name="nopassTransiton">  
      <string value="" />  
    </property>  
    <on event="start">  
      <event-listener class="test.com.yy.ah.SetBuyEquipmetnCounterSignUsers" />  
    </on>  
    <transition g="-41,-8" name="to 会签结果判断" to="会签结果判断" />  
  </custom>

  在这个定义中主要有两个类,一个是CountersignActivity,一个是AllAgreeStragy,另外还有一个分配子任务的类。其实现本身不复杂,也是利用子任务,但却实现了最大的发挥自由度。感兴趣的同学可以通过链接进一步学习其思路和实现方案。

4.4 assignHandler

  通过assigHandler实现会签的思路也与我们的思路相似,即子任务,也不做赘述。定义如下:

 <task g="182,379,92,52" name="审批">  
      <assignment-handler class="org.jbpm.examples.attendance.commercialtrip.CommercialTripAssignment"></assignment-handler>  
      <transition g="147,329:-47,-17" name="审批不通过" to="申请"/>  
      <transition name="审批通过" to="end1" g="-47,-17"/>  
 </task>

  

时间: 2024-12-12 20:45:27

jbpm会签的实现的相关文章

揭秘jbpm流程引擎内核设计思想及构架

作者 胡长城(银狐999) 1     前言 2     阅读本篇的基础准备 2.1      概念的基础 2.2      环境的基础 3     什么是流程引擎内核? 4     引擎内核所关注的四个主要问题 4.1      模型与定义对象 4.2      调度机制与算法 4.3      执行机制与状态 4.4      实例对象与执行环境 5    jbpm,“精简”的开源流程引擎 6    jBpm流程模型与定义对象 6.1      首先解决如何形式化描述一个流程的问题 6.2 

jbpm的智能选择审批人及人工任务分配的实现思路

一.jbpm中审批人的概念 在工作流中每一个人工任务的办理者被称作审批人,在原生的jbpm定义中,我们可以看到assignee和assignmentHandler这两个标签. <task name="review" g="96,16,127,52">       <assignment-handler class="org.jbpm.examples.task.assignmenthandler.AssignTask"> 

jBPM4.3+ssh+会签 整合配置及完整实例

大佬们的项目里有用到会签,所以趁双休日研究了下. 其实也是简单的会签情况,不过开始的时候研究了4.4,(因为先前研究的都是4.4),发现4.4跟4.3的处理方法完全不一样,搞的我比较郁闷……弄了一天,都是一个老问题,就是在历史记录表中查不到记录.后来查了很多资料,才觉悟4.4的处理方式确实不同于4.3. 4.3中的实现还是很简单的.实例中使用custom节点. 例子是前几次实例中的请假,就很简单的申请——manager和boss进行会签——同意则继续,不同意返回. 下面是主要的类及说明: pac

jbpm人工终止的开发

jbpm人工终止功能的开发 人工终止即管理员在管理界面通过某种技术手段将停留在任意节点的审批中的流程终止掉.目前的需求场景是大量的如加班.请假.外出和一些行政类别的审批单停留在直接或越级主管审批(部分中层或高层的单子,其直接或越级是EMT总裁或CEO),相应审批人未及时审批,导致后续工作存在困难. 首先将终止功能开放给系统管理员或该流程的流程管理员,流程管理员或系统管理员可以将该类型的单子终止掉,人工终止的单子属于特殊类型的单子,有所谓的死单,比如发起人已离职或该单已失效,甚至是单子是否审批通过

Jbpm自由流的实现

一.需求定义: 1.允许向已办理过的任意节点流转:从历史任务表中读取以前办理过的任务,从当前任务指向该历史任务节点,并创建该历史节点的新任务,并将原历史任务的审批人分配给现历史任务; 如ABCDE五个节点,目前停留在D节点,点击按钮,跳出包含A.B.C.D下拉菜单的页面,例如选择B,创建D到B的流向,创建基于B的新任务,将历史任务B的审批人分配给新任务B(也应允许重新为新任务B分配审批人),同时向该审批人发送邮件,删除D到B的流向: 2.在历史任务表中应体现以上过程,保留流转的历史痕迹: 3.该

JBPM API初识

JBPM为我们提供了一系列管理流程的服务.从定义流程,到实例化流程定义,流程实例执行过程中,对流程的管理,流程结束后,纳入历史流程,进行管理.JBPM的流程管理,提供了完整的API,提高了流程执行的效率. JBPM提供的服务API为我们实现了: (1)流程部署 (2)流程实例 (3)流程任务 (4)流程历史 ProcessEngine提供了6个服务API.ProcessEngine是由Configuration类构建的,即工作流引擎根据配置产生. (1)RepositoryService--流程

JBPM工作流(八)——流程实例(PI)Process Instance

/** * 流程实例 *    *  启动流程实例 *    *  完成任务 *    *  查询 *      *  查询流程实例 *      *  查询任务 *          *  查询正在执行的任务 *            *  查询所有的正在执行的任务 *            *  根据任务的执行人查询正在执行的任务 *            *  根据executionId查询正在执行的任务 *            *  根据piid查询正在执行的任务 *         

JBPM(四)——把流程部署到服务器上

当我们的业务流程被设计开发完毕之后,会有许多相关的文件"散落"在工程中,其中包括: 定义流程的JPDL文件 根据图形化流程定义同步生成的流程图片文件(PNG格式) 业务流程中用于人机交互的表单页面文件 事件监听器等用户自定义代码的Java类文件 其他流程资源文件,例如小图标.css样式表.脚本文件.属性文件等 jbpm4支持将流程定义及其相关资源打包一个JAR(Java归档)格式的文件,部署到服务器上(其实就是服务所连接的JBPM数据库中),然后流程定义就可以被执行了. 一.如何将流程

JBPM(一)——工作流基础

1.什么是工作流? 全部或者部分由计算机支持或自动处理的业务过程. 2.工作流的目标? 管理工作的流程以确保工作在正确的时间被期望的人员所执行 3.工作流的好处 例如: 简单的业务流程--订货流程: 1>客户提交采购订单 2>业务员执行订单处理 3>如果缺货,转工厂生产 4>仓库发货 5>物流发货 整个流程如图所示: 如果不使用工作流技术,从头开始开发这个订购流程的业务系统,我们需要做 每个活动节点都要开发交互界面和后台处理程序 每次活动的流转都需要硬性判断下一步活动节点及其