[jbpm]jBPM(十):webSale的"页面流"介绍

来源:互联网 发布:linux vi 退出不保存 编辑:程序博客网 时间:2024/05/14 19:33

 通过前面几篇博客,我们看到了jBPM自带例子webSale可以在Tomcat+Mysql的环境中运行了. 这也是我研究jBPM的第一步. 希望对jBPM有个目无全牛地了解/理解/掌握,这里有必要介绍下这个webSale例子, 毕竟它是通往"全牛"的引子, 同时也可以作为项目中调用jBPM的一个不错practice.

  这里采用"页面流" 方式(也就是顺着页面的跳转)来展开对webSale的介绍,及其背后调用的jBPM的相关API.另由于这个webSale是用JSF来作显示的,对JSF不熟悉的看官可找些文档看下,以下的介绍中不会再做JSF方面的介绍.

  第一步, 进入登录界面. 这时页面上以下拉菜单方式给出webSale支持的用户名, 这些用户名也正是流程中task的执行者. 那这些用户名是如何获得的? UserBean的getUsers方法里, 执行了这样调用:

  new IdentitySession(JbpmContext.getCurrentJbpmContext().getSession()).getUsers(). // 注,为了行文方便,我这里更紧凑地改写了原代码, 以下同.

  第二步, 选一个用户后, 点"Log In"按钮时, 对应的login方法是, 执行JbpmContext.getCurrentJbpmContext().setActorId(userName)设置actor. 跳转到home页面(对应着home.jsp文件).

  在home页面中, webSale做了两件事: 显示当前登录用户负责的Tasklist, 显示已经发布的流程. 下面看这些数据库是怎么来的.

  显示当前登录用户负责的Tasklist时, 背后执行了taskMgmtSession.findTaskInstances(currentUserName)语句, 这个返回一个装有TaskInstance的list, 再在页面上遍历list以 "taskInstance.taskMgmtInstance.taskMgmtDefinition.processDefinition.name/version" 方式取出流程定义中的name和version信息, 并给每一个taskInstance的Name加了一个执行链接调用homeBean中的selectTaskInstance方法.

  显示已经发布的流程时, 背后执行graphSession.findLatestProcessDefinitions(), 在JSP页面里, 以processDefinition.taskMgmtDefinition.startTask.name方式获得流程的首任务名,并给些任务名加链接去执行homeBean的startProcessInstance方法.

  第三步, 在上一步返回的home页面中, 点任务名链接, 调用startProcessInstance方法来启动流程处理. 此方法中先执行"new ProcessInstance(graphSession.loadProcessDefinition(processDefinitionId)). getTaskMgmtInstance().createStartTaskInstance()"来启动流程, 再通过"jbpmContext.save(processInstance)"保存上面new出来的processInstance. 调用taskBean中的initialize(taskInstance)处理前面createStartTaskInstance方法返回的 taskInstance为下一页面的显示做准备. 跳转到task页面.

  第四步, task页面中展现数据/流程定义图片.

  先说这里简单的(调用简单,但背后的实现还是挺复杂的)图片展现: <jbpm:processimage task="${taskBean.taskInstanceId}"/>.

  接着看数据显示, 其实这一块的工作都是在上面taskBean中的initialize(taskInstance)方法做好的. 那这个方法又做了些什么呢? 两件事: 显示跟当前taskInstance绑定的variable信息及当前taskInstance的transition(也就是针对当前 taskInstance都有什么样的控制).

  variable信息这样得到: taskInstance.getTask().getTaskController().getVariableAccesses(){variableAccess | variableAccess .getMappedName ==> mappedName, taskInstance.getVariable(getMappedName) => value, new TaskFormParameter(variableAccess, value)}. 好像是用了类似于python/groovy/ruby那样的可执行的伪代码. 这些可执行的伪代码也打开了设计新编程语言的可能性.

  当前taskInstance的transition又是这样得到: taskInstance.getAvailableTransitions.

  第五步, 在上一步的基础上, 从本质上来看,填写必要信息后有两种操作:保存当前信息并不结束当前taskInstance, 保存当前信息并结束当前taskInstance使流程进入下一taskInstance. 这两个操作分别对应着两个方法save和saveAndClose-- 这个saveAndClose方法中有调用save方法.

  先看save方法,它做了两件事: "taskFormParameter.isWritable && taskFormParameter.getValue ==> taskInstance.setVariable(taskFormParameter.getLabel(), taskFormParameter.getValue())" 更新taskInstance中相应的variable信息; jbpmContext.save(taskInstance).

  saveAndClose方法中三件事: 调用taskInstance.end结束当前taskInstance; processInstance.getLoggingInstance().getLogs(TaskAssignLog.class){ | getTaskNewActorId}显示下一taskInstance的负责人; jbpmContext.save(taskInstance).

  至此, 我们采用第二步返回页面中的startProcessInstance走了一遍, 若采用selectTaskInstance的话,"页面流" 会直接跳到第四步中的task页面, 就不再另行介绍.