最近老板心血来潮要搞基于activiti的工作流,没办法,只能现学,看了两周,一个小总结。 前提准备:
- eclipse安装acidity-designer插件
- 了解bpmn2.0基本知识
- 下载activiti,跑一跑其中demo
- 下载咖啡兔中的kft-activiti-demo
基于kft-activiti-demo 中的leave-formkey改造,主要是为了学习bpmn流程图表制作,发布流程,对应的api,相关数据库表,顺便复习下springmvc。
- 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);