activity初探(基于kft-activiti-demo的一个小例子)

最近老板心血来潮要搞基于activiti的工作流,没办法,只能现学,看了两周,一个小总结。 前提准备:
- eclipse安装acidity-designer插件
- 了解bpmn2.0基本知识
- 下载activiti,跑一跑其中demo
- 下载咖啡兔中的kft-activiti-demo



基于kft-activiti-demo 中的leave-formkey改造,主要是为了学习bpmn流程图表制作,发布流程,对应的api,相关数据库表,顺便复习下springmvc。

  1. Bpmn流程图表制作

前提熟悉基本的bpmn2.0规范,熟悉eclipse插件acitviti-desinger使用。画出流程如下:

对应图表和每个控件属性如下:(task控件中的general选项主要定义id和name,可随意填写,故没有展示)

图表:

注意id取值,这里的id就是在启动流程时根据该id获取实例,如下:

repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave-formkey")。

此id可以重复使用。因为后面要将该实例部署到kft-activiti-demo的外置表单流程中,而kft-activiti-demo中外置表单流程里一些调用sql是写死的,所以为了方便,这里直接用该id就行

Start:

注意initiator:
其作用设置一个变量名称,可以是任意的字符串,变量applyUserId保存申请用户的ID
在需要设置申请用户才能办理的任务上设置activiti:initiator
对应用户手册上两个关键函数

identityService.setAuthenticatedUserId("kafeitu")//设置当前的用户ID,而且这行代码需和activiti:initiator配合使用
runtimeService.startProcessInstanceByKey("leave")//启动流程,判断有没有activiti:initiator属性,如果有把属性activiti:initiator的值作为一个变量添加到流程实例中

班主任审批:

书记审批:

上面两个task中都定义了一个外置表单,实际上就是一个html文件,在流程流转到当前task时引擎会自动加载对应的外置表单。因为业务逻辑一样,所以这里直接copy了kft-activiti-demo 中的leave-formkey activiti diagram中的申请、审核表单。

两个task分别定义了一个candidate group name,实际上就是角色身份,就是说只要用户身份中包含teacher,schoolmaster就能签收办理该task。对应初始化sql:

insert into ACT_ID_GROUP values ('teacher', 1, '老师', 'assignment');
insert into ACT_ID_GROUP values ('schoolmaster', 1, '书记', 'assignment');

此外,还需要给用户分配group,为了方便,这里将当前用户公用一个身份,对应sql:

insert into ACT_ID_MEMBERSHIP values ('leaderuser', 'teacher');
insert into ACT_ID_MEMBERSHIP values ('leaderuser', 'schoolmaster');

上面的ACT_ID_GROUP和ACT_ID_MEMBERSHIP都是activiti自带的表,分别表示group定义和用户所属group的关系。这个在后面的数据库表中将详细介绍。

至于怎么执行sql,这里就不详细说了,kft-activiti-demo中sql目录下有h2,mysql,oracle对应的数据初始化脚本,可以把上面的数据插入其中,在首次初始化时执行,也可通过命令行或者其他工具一条条插入。

顺序流:
这里只有两条标准顺序流
同意:

注意其中的deptLeaderPass,这是在上一个班主任审批外置form中定义的一个是否同意的变量。

不同意:

End:
缺省值

最后项目生成文件:

2. 打包&部署

打包:
将上面5个文件,即bpmn文件和对应的png及相关form打包成zip,直接用eclipse自带的打包:
Export->archive file->选择保存路径->(注意option中选择save in zip format)
部署:项目启动后:

右上角点击部署流程:

选中打包的zip,点击submit

3.后台跟踪及相关数据库表

为了方便了解后台的流程,这里将每一步调用的文件及方法列出,并列出涉及的表:

3. 1.部署

/
*
部署函数
*/
me.kafeitu.demo.activiti.web.workflow.ActivitiController.java
public String deploy()
其中两个重要方法:
Deployment deployment = repositoryService.createDeployment().addZipInputStream(zip).deploy();
 List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();

其实就是部署和列取部署的流程定义,具体函数定义可参见,下载activiti安装包中说明:
activiti-5.18.0/activiti-5.18.0/docs/javadocs/index.html
涉及表:
ACT_RE_PROCDEF(流程定义表)
ACT_RE_DEPLOYMENT(部署信息表)

3. 2.列出流程(外置表单类型)

/*
列出所有外置表单
*/
Me.kafeitu.demo.activiti.web.form.formkey.FormKeyController.java //方法所在路径
public ModelAndView processDefinitionList()
关键方法:
 ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery().processDefinitionKey("leave-formkey").active().orderByDeploymentId().desc();

涉及表:
ACT_RE_PROCDEF(流程定义表)

3. 3.启动具体流程


/*
启动实例,读取启动环节的外置表单
*/
Me.kafeitu.demo.activiti.web.form.formkey.FormKeyController.java
public Object findStartForm()
关键函数:
Object startForm = formService.getRenderedStartForm(processDefinitionId);
//根据实例id获取表单

此时弹出渲染的表单:

填写内容后,点击“启动流程”

/**
     * 读取启动流程的表单字段
     */
Me.kafeitu.demo.activiti.web.form.formkey.FormKeyController.java
 public String submitStartFormAndStartProcessInstance()

相关表:
ACT_RU_EXECUTION(执行中流程执行)
ACT_RU_VARIABLE(实时变量)
ACT_HI_VARINST(历史变量信息)
ACT_RU_IDENTITYLINK(身份联系)
ACT_HI_IDENTITYLINK(历史身份信息)
ACT_HI_PROCINST(历史流程实例信息)核心表
ACT_HI_ACTINST(活动实例信息)
ACT_HI_DETAIL(历史详细信息)

以上是该步骤涉及的重要表,还有一些表未列出,可以在程序执行的debug信息中了解到更为详尽的细节,包括sql语句,后面为了节省页面时间,也不再将列出想关表。每张表结构及信息可自行百度之。

3. 4.查看当前任务

   /**
     * task列表
     *
     * @param model
     * @return
     */
Me.kafeitu.demo.activiti.web.form.formkey.FormKeyController.java
public ModelAndView taskList()
关键函数:
根据定义的签收人或者候选group中获取满足当前用户的当前任务
 NativeTaskQuery query = taskService.createNativeTaskQuery().sql(sql)
                .parameter("processDefinitionKey", "leave-formkey").parameter("suspensionState", SuspensionState.ACTIVE.getStateCode())
                .parameter("userId", user.getId());

这里可以在函数中看看sql的具体写法。

3. 5.任务签收

 /**
     * 签收任务
     */
Me.kafeitu.demo.activiti.web.form.formkey.FormKeyController.java
public String claim()
关键函数:
taskService.claim(taskId, userId);//用户签收任务,言简意赅

3. 6.任务办理

  /**
     * 读取Task的表单
     */
Me.kafeitu.demo.activiti.web.form.formkey.FormKeyController.java
public Object findTaskForm()
关键函数:
Object renderedTaskForm = formService.getRenderedTaskForm(taskId);//读取当前task的外置表单

此时弹出渲染的表单:


执行完毕后:

当前任务变成了书记审批,因为当前用户兼顾“老师”,“书记”身份。
此后的签收办理环节同前面“班主任审核”环节类似。

3. 7.结束环节

/**
     * 办理任务,提交task的并保存form
     */
Me.kafeitu.demo.activiti.web.form.formkey.FormKeyController.java
public String completeTask()
关键函数:
identityService.setAuthenticatedUserId(user.getId());//最后环节将任务交给提交任务的用户
formService.submitTaskFormData(taskId, formProperties);
时间: 2024-09-29 10:42:13

activity初探(基于kft-activiti-demo的一个小例子)的相关文章

c语言基础-a与&amp;amp;amp;a比较时一个小例子的输出问题

问题描述 a与&a比较时一个小例子的输出问题 输出:p3+1=BCD,p4+1=BCD 本来以为输出应该是B int main(){ char a[5]={'A','B','C','D'}; char(*p3)[1]=&a; char(*p4)[1]=a; printf("p3+1=%s,p4+1=%s",p3+1,p4+1); return 0; } 另问:char(*p3)[1]=&a;匿名数组长度>=5时,是否溢出?请详细解释. 解决方案 试试pri

一个小例子解释如何来阻止Jquery事件冒泡_jquery

什么是JS事件冒泡? 在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window). 如何来阻止Jquery事件冒泡? 通过一个小例子来解释 <!DOCTYPE html PUBLIC "-//W3C//D

【JSP开发】有关session的登录注销的一个小例子

下面是一个session的应用的小例子,是用来注销登录的 登陆界面的代码: login.html: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>login.html</title> <meta http-equiv="keywords" content="keywor

netbeans6.5开发JSF+Hibernate的一个小例子(原创)

问题描述 只是一个简单的小例子,希望能对初学者有点帮助我也只是一个初学者,其中的错误还请大家指出http://www.cnblogs.com/halgogo/archive/2009/01/11/1373730.html 解决方案 解决方案二:加油解决方案三:我也是在初学,多多交流解决方案四:加油!

Gridview行上下移动自己做的一个小例子(第一种方法)

今天没有什么事做,就写了一个GridView行上下移动的小例子. 方法有好多种,我先写第一种. 没有什么技术含量 思路: 把要上移或下移的id 与它的临近行的id进行互换 效果: 前台页面: 1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="GridView2.aspx.cs" Inherits="WebApplication3.GridView2"

简单通俗易懂:一个小例子完美解释Naive Bayes(朴素贝叶斯)分类器

更多深度文章,请关注:https://yq.aliyun.com/cloud 最简单的解决方案通常是最强大的解决方案,而朴素贝叶斯就是一个很好的证明.尽管机器学习在过去几年取得了巨大的进步,但朴素贝叶斯已被证明不仅简单,而且快速.准确.可靠.它已经成功地用于许多项目中,而且它对自然语言处理(NLP)的问题的解决提供了很大的帮助. 朴素贝叶斯是利用概率论和贝叶斯定理预测样本类别(如新闻或客户评论)的概率算法.它们是概率性的,这意味着它们计算给定样本的每个类别的概率,然后输出概率最高的样本类别.他们

一个小例子对多态简单的理解

class Parent{     int age;     String name;     public Parent(String name, int age){         this.name = name;         this.age = age;     }     public void writeWay(){         System.out.println("毛笔!");      }   }     class Child extends Parent

Python连接DB2操作的一个小例子

QQ交流群:127591054 作者:JackChiang 作者QQ:595696297 Python版本3.5 这个小项目,是解决数据库查看的时候一些错误的,查看.每天都会跑数据,但是第一天的数据和第二天的名字可以是一样的,我第二天还可以在跑一遍. 涉及到的知识: 1.日期获取,例如获取2012-02-21~2013-08-21之间所有的日期列表,需要一天一天查询遍历. 2.正则匹配名字,由于一个调度会生成4条数据,需要找到这4条数据的顺序必须固定才为正确否则就是不对的. 3.然后把查询出来有

简单的并发编程中犯2的一个小例子--CAS使用时一定要考虑下是否有必要做轮询

并发编程我自己写过不少文章,不过我由于其相对需要理解更多的东西,我自己写代码也有时长犯2的时候,对于这些犯2的问题,我们只能将它作为自己宝贵的经历和财富,本文是很简单Java并发方面的小文章,为啥?因为是一个犯2的例子,这里给大家做个简单分享. 先简单描述下场景: 在一个app中,我需要为访问者提供某种信息的存储,由于架构上已经确定的方式,所以可以确保每一个app上存储的用户不会太多,于是就放在了内存中,而不是缓存. 这些信息需要定期清理掉,就像会话一样,每个用户都会有一个唯一的key标识符,用