无论是通过哪种方式设计好流程模版并部署到BDF2系统当中,一旦部署成功之后,接下来就可以对流程模版进行配置了,这里需要注意的是,一般情况下,我们在设计流程模版时(也就是在画流程图的时候)不需要对任务节点做太多配置(唯一要做的就是为其赋一个正确的名称),所以关于任务节点的配置都是在BDF2当中提供的配置与监控当中实现。
在BDF2当中提供的配置与监控当中,选中要配置的流程模版,点击工具栏上的“节点配置”按钮,系统会弹出一个dialog,并在所有的任务节点上添加链接,点击这个链接会弹出与这个任务节点相关的配置信息,如下图所示:
从弹出的窗口当中可以看出,对于任务节点,我们可以在线配置的内容有四块:第一个就是当前任务节点对应处理表单页面,它可以是一个标准的dorado view(比如aa.bb.cc.Demo.d),也可是一个标准的JSP;第二个是配置任务的处理人,也就是任务分配,就是决定在这个节点上产生的任务由谁来处理;第三个是定义任务在产生以后如何提醒任务处理人(发站内消息、邮件或其它);第四个任务过期就是可以给任务一个处理时间,一旦超过个时间还没有人处理,那么就通知任务处理人或做些其它动作。
我们首先来看看“任务分配”页中的配置内容,如下图所示:
点击“添加”在弹出的窗口当中选择我们采用的任务分配器,但可以看到弹出窗口是空的,这是因为在选择任务分配器前,我们还需要将要采用的任务分配器加载到系统当中,具体做法就是点击菜单导航中的“任务分配管理”,在其中添加我们要采用的任务分配器,如下图所示:
从上图当中可以看出,任务分配方式列表中,默认系统只提供了两种,对于用户来说,一般情况下,我都都需要定义自己的任务分配方式,如果需要定义,那么我们可以实现一个IAssignmentProvider接口的实现类,这个接口源码如下:
package com.bstek.bdf2.jbpm4.view.assignment.provider; import java.util.Collection; import org.jbpm.api.model.OpenExecution; import com.bstek.bdf2.jbpm4.model.AssignmentInfo; import com.bstek.bdf2.jbpm4.model.PrincipalDef; /** * @author Jacky.gao * @since 2013-3-23 */ public interface IAssignmentProvider { /** * @return 返回配置页面所在的URL */ String getUrl(); /** * @return 返回配置类型的ID */ String getTypeId(); /** * @return 返回与配置类型ID对象的Name描述 */ String getTypeName(); /** * @param assignmentDefId 任务分配定义的ID * @return 根据任务分配定义的ID返回与之对应的任务分配信息 */ Collection<AssignmentInfo> getAssignmentInfos(String assignmentDefId); /** * 删除指定分配定义下的分配定义信息 * @param assignmentDefId 分配定义信息的ID */ void deleteAssignmentInfos(String assignmentDefId); /** * @param assignmentDefId 任务分配定义的ID * @param execution 当前流程实例执行上下文对象 * @return 根据任务分配定义的ID返回所有与之对应的任务处理人的PrincipalDef集合 */ Collection<PrincipalDef> getTaskPrincipals(String assignmentDefId,OpenExecution execution); /** * @return 是否禁用 */ boolean isDisabled(); }
实际上,我们看到的系统当中默认提供的两种任务分配方式:流程实例发起人与指定一个用户,它们都是通过实现IAssignmentProvider接口,然后配置到Spring当中才出现在上图中的下接列表当中的。所以如果我们要定义自己的,同样要实现IAssignmentProvider接口。
如果不想系统默认提供的流程实例发起人出现在列表中,那么可以将bdf2.jbpm4.disablePromoterAssignment属性设置成true,同样对于指定一个用户的任务分配方式,如果不需要那么就将bdf2.jbpm4.disableSpecifyUserAssignment属性设置成true即可。
实际上,BDF2默认提供的两种任务分配方式:流程实例发起人与指定一个用户,就是给我们对如何编写IAssignmentProvider接口实现类提供了两种不同类型的示例。对于流程实例发起人这种任务分配方式,在使用不需要界面配置,所以它的实现类相对简单,其源码如下:
package com.bstek.bdf2.jbpm4.view.assignment.provider.impl.promoter; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.apache.commons.lang.StringUtils; import org.jbpm.api.model.OpenExecution; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.bstek.bdf2.jbpm4.model.AssignmentInfo; import com.bstek.bdf2.jbpm4.model.PrincipalDef; import com.bstek.bdf2.jbpm4.service.IBpmService; import com.bstek.bdf2.jbpm4.view.assignment.provider.IAssignmentProvider; /** * 流程发起人任务分配方式 * @author Jacky.gao * @since 2013-3-23 */ @Component public class PromoterAssignmentProvider implements IAssignmentProvider { @Value("${bdf2.jbpm4.disablePromoterAssignment}") private boolean disabled; @Autowired @Qualifier(IBpmService.BEAN_ID) private IBpmService bmpService; public String getUrl() { return null; } public String getTypeId() { return "promoter"; } public String getTypeName() { return "流程实例发起人"; } public Collection<AssignmentInfo> getAssignmentInfos(String assignmentDefId) { List<AssignmentInfo> info=new ArrayList<AssignmentInfo>(); AssignmentInfo a=new AssignmentInfo(); a.setName("流程实例发起人"); a.setValue("从流程实例中取名为["+IBpmService.PROCESS_INSTANCE_PROMOTER+"]的变量值,这个变量值表示流程实例发起人用户名"); info.add(a); return info; } public Collection<PrincipalDef> getTaskPrincipals(String assignmentDefId,OpenExecution execution) { List<PrincipalDef> usernames=new ArrayList<PrincipalDef>(); String username=(String)execution.getVariable(IBpmService.PROCESS_INSTANCE_PROMOTER); if(StringUtils.isEmpty(username)){ throw new RuntimeException("Variable not found ["+IBpmService.PROCESS_INSTANCE_PROMOTER+"] in current process instance"); } PrincipalDef p=new PrincipalDef(); p.setId(username); usernames.add(p); return usernames; } public void deleteAssignmentInfos(String assignmentDefId){ //do nothing } public boolean isDisabled(){ return disabled; } }
但对于指定一个用户这种任务分配方式,因为涉及到页面,相比之下就复杂一些,我们来看看它的源码:
package com.bstek.bdf2.jbpm4.view.assignment.provider.impl.specifyuser; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.hibernate.Session; import org.jbpm.api.model.OpenExecution; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.bstek.bdf2.jbpm4.Jbpm4HibernateDao; import com.bstek.bdf2.jbpm4.model.AssignmentInfo; import com.bstek.bdf2.jbpm4.model.InternalAssignment; import com.bstek.bdf2.jbpm4.model.PrincipalDef; import com.bstek.bdf2.jbpm4.view.assignment.provider.IAssignmentProvider; /** * 指定一个用户作为任务处理人 * @author Jacky.gao * @since 2013-3-23 */ @Component public class SpecifyUserAssignmentProvider extends Jbpm4HibernateDao implements IAssignmentProvider { @Value("${bdf2.jbpm4.disableSpecifyUserAssignment}") private boolean disabled; public String getUrl() { return "bdf2.jbpm4.view.assignment.provider.impl.specifyuser.SpecifyUserProvider"; } public String getTypeId() { return "specify_user"; } public String getTypeName() { return "指定一个用户"; } public Collection<AssignmentInfo> getAssignmentInfos(String assignmentDefId) { String hql="from "+InternalAssignment.class.getName()+" where assignmentDefId=:assignmentDefId"; Map<String,Object> map=new HashMap<String,Object>(); map.put("assignmentDefId", assignmentDefId); List<InternalAssignment> internals=this.query(hql, map); List<AssignmentInfo> infos=new ArrayList<AssignmentInfo>(); for(InternalAssignment internal:internals){ AssignmentInfo info=new AssignmentInfo(); info.setName("一个用户"); info.setValue(internal.getName()); infos.add(info); } return infos; } public Collection<PrincipalDef> getTaskPrincipals(String assignmentDefId,OpenExecution execution) { String hql="from "+InternalAssignment.class.getName()+" where assignmentDefId=:assignmentDefId"; Map<String,Object> map=new HashMap<String,Object>(); map.put("assignmentDefId", assignmentDefId); List<InternalAssignment> internals=this.query(hql, map); List<PrincipalDef> result=new ArrayList<PrincipalDef>(); for(InternalAssignment internal:internals){ PrincipalDef def=new PrincipalDef(); def.setId(internal.getValue()); result.add(def); } return result; } public void deleteAssignmentInfos(String assignmentDefId){ String hql="delete "+InternalAssignment.class.getName()+" where assignmentDefId=:assignmentDefId"; Map<String,Object> map=new HashMap<String,Object>(); map.put("assignmentDefId", assignmentDefId); Session session=this.getSessionFactory().openSession(); try{ session.createQuery(hql).setString("assignmentDefId", assignmentDefId).executeUpdate(); }finally{ session.flush(); session.close(); } } public boolean isDisabled() { return disabled; } }
可以看到,指定一个用户这种任务分配方式当中用到的页面是通过实现类当中的getUrl方法返回的,这个返回的页面是bdf2.jbpm4.view.assignment.provider.impl.specifyuser.SpecifyUserProvider,实际上这是一个标准的dorado7 view文件,我们可以在BDF2-JBPM4源码包中找到bdf2.jbpm4.view.assignment.provider.impl.specifyuser包下的名为SpecifyUserProvider.view.xml文件,具体页面中的实现大家可以参考这个view文件,值得注意的是,这里的getUrl方法返回的页面只能是一个标准的dorado7 view,而不能是JSP或其它,因为返回的URL会被系统采用dorado7中的subviewholder引入到父页面当中,而subviewholder中的页面只能是标准的dorado7 view。
定义一个任务分配方式,确认后,再次打开任务节点配置界面,就可以看到定义的任务分配方式,如下图所示:
任务处理人配置好之后,就可以利用这个配置与监控对流程模版进行测试了,通过点击工具栏上的“创建实例”按钮就可以创建一个新的流程实例,以这个流程模版为例,新的流程实例产生后,流程将会流转到初审节点,右上边的任务列表中也会出现这个初审节点上产生的任务,点击其上的“查看流程图按钮”,可以看到当前流程实例所处位置,如下图所示:
Attachments:
task_assign.png (image/png)
assign_maanger.png (image/png)
specify-user.png (image/png)
process-img.png (image/png)