欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 1970-01-01 07:57:24
...

        通过前面几篇博客,我们看到了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页面, 就不再另行介绍.
--------------------------------
   快要写完本博客了, 有些感悟:
        0, 为什么要整理这么个文字版的webSale描述呢? 一是为了把现在的记忆以文字形式保存下来, 以后查看时不必再去看webSale中JSP到JavaBean的跳转. 更重要的是为了后续博客的引用, 也即当要描述一个jBPM API时不必再介绍它的应用场景,直接给出这里是第几步即可.
        1, 上面这些描述用时序图来表达会简洁明了的多.
        2, 体会到像Python那样的可执行伪代码的好处: 直接用Python这样的动态语言来"写"文档.