- 工作流概念
工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。
工作流管理系统(Workflow Management System, WfMS)是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流逻辑进行工作流实例的执行。工作流管理系统不是企业的业务系统,而是为企业的业务系统的运行提供了一个软件的支撑环境。
- Activiti简单介绍
Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。Activiti基于Apache许可的开源BPM平台,创始人Tom Baeyens是JBoss jBPM的项目架构师,它特色是提供了eclipse插件,开发人员可以通过插件直接绘画出业务流程图。
- activiti是一个工作流引擎,Activiti工作的核心,负责生成流程运行时的各种实例及数据、监控和管理流程的运行。
- 在IDEA安装acti插件
- 了解activiti的目录结构
- 目录结构看名字也就知道什么意思
- 工作流框架底层需要有数据库支持,activiti5.13版本对应23张表,activiti框架底层使用mybatis操作数据库。
- JBPM也是一个工作流框架,JBPM4.4底层18张表,底层使用hibernate操作数据库。
- BPMN
业务流程建模与标注(Business Process Model and Notation,BPMN) ,描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram)
- activiti的入门教程
- 导入activiti所需要的数据表
- 这里使用mysql,所以导入database文件夹下面三个sql文件
- 新创建一个数据来存表
- 23张表如图
-
- 了解数据库表前缀代表的函数
Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。
- ACT_RE_*: 'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
- ACT_RU_*: 'RU'表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
- ACT_ID_*: 'ID'表示identity。 这些表包含身份信息,比如用户,组等等。
- ACT_HI_*: 'HI'表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
- ACT_GE_*: 通用数据, 用于不同场景下。
-
- 使用框架自动生成表(不建议)
步骤:
-
-
- 第一步:创建一个java项目
- 第二步:导入activiti中wars程序的所有jar包
- 第三步:再导入一个mysql的数据库驱动
- 第四步:提供一个配置文件,配置文件名必需为activiti-context.xml
-
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 流程引擎配置对象 --> <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql:///activiti_day1"/> <property name="jdbcUsername" value="root"/> <property name="jdbcPassword" value="123456"/> <property name="databaseSchemaUpdate" value="true"/> </bean>
<!-- 使用工厂创建流程引擎对象 --> <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration"/> </bean> </beans> |
-
-
- 第四步:写一个单元测试
-
- 只要获取流程引擎对象,就会自动创建表
- 可以添加示例程序的log4j.properties来查看日志里更多信息输出
- 在activiti-engine-5.13.jar有数据库sql文件,用于自动创建数据库表
import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.junit.Test;
public class Test1 { public void test1(){ ProcessEngine pe = ProcessEngines.getDefaultProcessEngine(); } } |
-
- 设计一个请假流程图
- 在Eclipse中,利用activiti插件创建一个请假流程图
- 在每一个任务中,找到Main config的Assignee中,先固定每个任务的受理人
-
- 部署流程定义
- 就是把流程存入数据库,写个单元测试代码
- 流程定义部署完后,会在act_re_deployment和act_re_procdef两张表存储数据,
- deployment的ID每次增加100
- 同一个流程的procdef表的version是递增的
public void test2(){ ProcessEngine pe = ProcessEngines.getDefaultProcessEngine(); //创建部署构建器对象 DeploymentBuilder db = pe.getRepositoryService().createDeployment();
//读取流程定义文件(bpmn,png) db.addClasspathResource("qjlc.bpmn"); db.addClasspathResource("qjlc.png");
//部署定义流程 Deployment deployment = db.deploy(); System.out.println(deployment.getId()); } |
-
- 查询流程定义
public void test3(){ ProcessEngine pe = ProcessEngines.getDefaultProcessEngine(); ProcessDefinitionQuery query = pe.getRepositoryService().createProcessDefinitionQuery();
List<ProcessDefinition> list = query.list(); for(ProcessDefinition pd : list){ System.out.print("ResourceName-" +pd.getResourceName() + ": "); System.out.print("id-" + pd.getId() + ": "); System.out.print("key-" + pd.getKey() + ": "); System.out.print("name-" + pd.getName() + ": "); System.out.println(); } } |
-
- 根据流程定义启动流程实例
- 就是把第一个请假申请任务跑
- 内部会操作act_re_execution和act_re_task两张表
public void test4(){ String pdId= "qjlc:1:304"; //启动流程实例 ProcessInstance pi = pe.getRuntimeService().startProcessInstanceById(pdId); System.out.println(pi.getId()); } |
-
- 查询个人任务
public void test5(){ //查询个人任务 TaskQuery tq = pe.getTaskService().createTaskQuery(); tq.taskAssignee("zhangsan"); tq.orderByTaskCreateTime().desc();//时间排序 List<Task> tasks = tq.listPage(0, 10);//分页查询 for(Task task : tasks){ System.out.println("================================="); System.out.println("taskId:" + task.getId()); System.out.println("taskName:" + task.getName()); System.out.println("executionId:" + task.getExecutionId()); } } |
-
- 办理个人任务
- 请求申请需要被处理,处理中会操作act_re_task和act_hi_taskinst表
- 处理事,会进入下一个任务,往task表插入下一个流程的任务,比如请假申请后,下一个任务就是项目经理审批任务
public void test6(){ String taskId = "604"; //根据任务id办理个人任务 pe.getTaskService().complete(taskId); } |
-
- 部署流程定义的另一种方式zip文件
public void test7() throws FileNotFoundException{ //创建部署构建器对象 DeploymentBuilder db = pe.getRepositoryService().createDeployment();
File file = new File("C:\\process.zip"); FileInputStream fis = new FileInputStream(file);
ZipInputStream zis = new ZipInputStream(fis); db.addZipInputStream(zis);
//部署定义流程 Deployment deployment = db.deploy(); System.out.println(deployment.getId()); } |
-
- 删除流程定义
public void test8(){ //pe.getRepositoryService().deleteDeployment("901"); //加个true,删除process表相关记录,如果启动流程了实例,用下面的方法删除 pe.getRepositoryService().deleteDeployment("901", true); } |
-
- 查询部署对应的流程定义文件名称和输入流
public void test9(){ String deploymentId = "301"; List<String> names = pe.getRepositoryService().getDeploymentResourceNames(deploymentId); for (String name : names) { System.out.println(names); //可以还原成文件,默认流程定义文件存在了act_ge_bytearr表 //InputStream in = pe.getRepositoryService().getResourceAsStream(deploymentId, name); } } |
-
- 查询部署对应的流程定义图表
@Test public void test10() throws IOException{ String processDefinitionId = "qjlc:1:304";//流程定义id InputStream pngStream = pe.getRepositoryService().getProcessDiagram(processDefinitionId); FileUtils.copyInputStreamToFile(pngStream, new File("c:\\t\\abc.png")); } |
-
- 删除流程实例
@Test public void test11(){ String processInstanceId = "401"; String deleteReason = "不请假了"; pe.getRuntimeService().deleteProcessInstance(processInstanceId , deleteReason ); } |
- Activity API总结
- 几个接口(和表有对应关系):
Deployment------act_re_deployment
ProcessDefinition-----act_re_procdef
ProcessInstance------act_ru_execution
Task-----act_ru_task
- 几个Query对象
DeploymentQuery------act_re_deployment
ProcessDefinitionQuery-----act_re_procdef
ProcessInstanceQuery------act_ru_execution
TaskQuery-----act_ru_task
- 几个Service
RepositoryService----操作部署表、流程定义表等静态资源信息表
RuntimeService----操作流程实例表、任务表等动态信息表
TaskService-----操作任务表
HistoryService----操作历史表
IdentityService----操作用户表、组表、关系表
- 流程变量
- 请假流程存在的问题
- 缺少请假原因和请假天数,后期可能还会有其它数据要补充
- activiti把这些数据称为流程变量,内部提供了一张act_ru_variable 表来存这些数据
-
- 设置流程变量的方式
- 重新创建一个Java项目和数据库,这次用个报销流程讲解
-
-
- 第一种:【启动流程实例时设置流程变量】
-
//1.获取流程引擎 ProcessEngine pe = ProcessEngines.getDefaultProcessEngine();
@Test public void test1(){
//2.获取部署构建器对象 DeploymentBuilder db = pe.getRepositoryService().createDeployment();
//3.添加流程资源 db.addClasspathResource("com/gyf/activiti/variable/bxlc.bpmn"); db.addClasspathResource("com/gyf/activiti/variable/bxlc.png");
//4.部署 Deployment deployment = db.deploy(); System.out.println(deployment.getId()); } /** * 启动流程实例时设置流程变量 * */ @Test public void test2(){ Map<String,Object> variables = new HashMap<String,Object>(); variables.put("bxyy", "成都出差机机票"); variables.put("bxje", "890"); pe.getRuntimeService().startProcessInstanceByKey("bxlc", variables); } |
-
-
- 第二种:【办理任务时设置流程变量】
-
/** *办理任务时流程变量 * */ @Test public void test3(){ String taskId = "304"; Map<String,Object> variables = new HashMap<String,Object>(); variables.put("bxyy", "北京出差机机票"); variables.put("bxje", "891"); pe.getTaskService().complete(taskId,variables); } |
-
-
- 第三种:【使用RuntimeService的set方法流程变量】
-
@Test public void test4(){ Map<String,Object> variables = new HashMap<String,Object>(); //variables.put("bxyy", "上海出差机票"); variables.put("审批意见", "同意");
pe.getRuntimeService().setVariables("301", variables); } |
-
-
- 第四种:【用TaskService的set方法设置】
-
@Test public void test5(){
Map<String,Object> variables = new HashMap<String,Object>(); variables.put("审批意见", "不同意"); pe.getTaskService().setVariables("404", variables); } |
-
-
- 注意:
-
- 如果设置的是自定义的类型,需要实现序列号接口
-
- 读取流程变量的方式
- 方式一【使用RuntimeService的get方法获取】
- 读取流程变量的方式
-
-
- 方式二【使用TaskService的get方法获取】
-
-
- 动态设置任务的候选人
- 第一步:在任务的Assignee写表达式
- 动态设置任务的候选人
-
-
- 第二步:在启动流程实现时,需要添加一个表达式里的变量值
-
- 组任务操作
- 候选人组任务(了解)
- 第一步:给任务添加多个用户
- 候选人组任务(了解)
-
-
- 第二步:重新部署流程和启动流程实现
- 第三步:办理第一个流程任务
-
-
-
- 第四步:根据用户id查询任务
-
-
-
- 第五步:拾取任务
-
-
- 候选组组任务(重点)
- 第一步:设置一个财务分组id
- 候选组组任务(重点)
-
-
- 第二步:重新部署流程并启动流程实例然后complete提交申请
- 第三步:添加组
-
-
-
- 第四步:添加用户
-
-
-
- 第五步:建立用户和组的关系
-
-
-
- 第六步:根据用户id或者组查询任务
-
- 注意:查询任务时,要先启动流程实现并输第一个任务
@Test public void testProcessInstance(){ //启动流程实例: Map<String,Object> variables = new HashMap<String,Object>(); variables.put("bxyy", "南京出差机机票"); variables.put("bxje", "890"); variables.put("employeeName", "小李"); pe.getRuntimeService().startProcessInstanceByKey("bxlc", variables); }
@Test public void testComplete(){ //处理第一个任务 pe.getTaskService().complete("2307"); } @Test public void test5(){ //查询组任务 TaskQuery tq = pe.getTaskService().createTaskQuery(); String userId = "1"; //tq.taskCandidateUser(userId); tq.taskCandidateGroup("财务组"); List<Task> tasks = tq.list(); for(Task t:tasks){ System.out.println(t.getId()); } } |
-
-
- 第七步:拾起任务
-
pe.getTaskService().claim("2402", "1"); |
- 排它网关
- 排它网关流程图
-
- 测试网关
- 在开启流程实例时,必需设置流量变量qjts
public class GateWayTest { //1.获取流程引擎 ProcessEngine pe = ProcessEngines.getDefaultProcessEngine();
@Test public void test1(){
//2.获取部署构建器对象 DeploymentBuilder db = pe.getRepositoryService().createDeployment();
//3.添加流程资源 db.addClasspathResource("com/huaizhi/activiti/gateway/qjlc.bpmn"); db.addClasspathResource("com/huaizhi/activiti/gateway/qjlc.png");
//4.部署 Deployment deployment = db.deploy(); System.out.println(deployment.getId()); }
@Test public void test2(){ Map<String,Object> variables = new HashMap<String,Object>(); variables.put("qjyy", "感冒.."); variables.put("qjts",5); pe.getRuntimeService().startProcessInstanceByKey("qjlc", variables);
} @Test public void test3(){ String taskId = "606"; pe.getTaskService().complete(taskId);
} } |
- activiti与spring整合
- applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql:///activiti_day2"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean>
<!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
<!-- 流程引擎配置对象 --> <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> <property name="dataSource" ref="dataSource"/> <property name="transactionManager" ref="transactionManager"/> </bean>
<!-- 使用工厂创建流程引擎对象 --> <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration"/> </bean> </beans>
|
-
- 单元测试
package com.huaizhi.activiti.springActivitiTest;
import java.util.List;
import org.activiti.engine.ProcessEngine; import org.activiti.engine.repository.ProcessDefinition; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringText {
@Test public void test1() { //1.创建spring工厂 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取bean ProcessEngine pe = (ProcessEngine) ac.getBean("processEngine");
List<ProcessDefinition> list = pe.getRepositoryService().createProcessDefinitionQuery().list();
//有流程定义打印,代表配置成功 for(ProcessDefinition pd : list){ System.out.println(pd.getKey()); } } }
|
- Bos项目集成activiti
- 第一步:在Bos数据库添加activiti所需要的表
- 第二步:将activiti与spring的整合转移到Bos项目中
- 导入jar包到项目【使用spring3.2以上版本,不需要添加spring-asm.jar 】
- spring中配置processengin
<!-- 流程引擎配置对象 --> <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> <property name="dataSource" ref="dataSource"/> <property name="transactionManager" ref="transactionManager"/> </bean>
<!-- 使用工厂创建流程引擎对象 --> <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration"/> </bean> |
- 再配置activiti的各种service
<!-- 注册Service --> <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/> <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/> <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/> <bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService"/> |
- 测试下是否能获取到流程定义
- 流程定义管理模型
- 修改系统管理的菜单数据
- 在admin.json 添加两行数据
{ "id":"1004", "pId":"100", "name":"流程定义管理", "page":"processDefinitionAction_list.action"}, { "id":"1005", "pId":"100", "name":"查看正在运行的流程实例", "page":"processInstanceAction_list.action"}
|
-
- 查看流程定义
- 创建ProcessDefinitionAction,完成流程定义列表展现
-
- 部署流程定义
-
- 查看流程定义图
第一步:修改jsp页面
<td> <a onclick="showPng('${id}')" class="easyui-linkbutton" data-options="iconCls:'icon-search'">查看流程图</a> </td> <script type="text/javascript"> function showPng(id) { var url = "${pageContext.request.contextPath}/processDefinitionAction_viewpng?id=" + id; //在新窗口中打开流程图 window.open(url); } |
-
- 删除流程定义
-
-
- 第一步:添加删除的js代码
-
function del(id){ var url = "${pageContext.request.contextPath}/processDefinitionAction_del?id=" + id; $.messager.confirm("确认信息","你确定要删除流程定义",function(r){ if(r == false) return; $.post(url, function(data){ if(data == 1){//删除成功 $.messager.alert("提醒","删除成功","info",function(){ //刷新页面 window.location.href = "${pageContext.request.contextPath}/processDefinitionAction_list"; }); }else{ //删除失败 $.messager.alert("提醒","删除失败"); } } ); }); } |
- 同步bos系统中用户和角色到activiti
- 删除数据库,把.sql的文件表创建下,导入auth_function表数据
- 内置一个admin帐号
- 配置文件中添加下面的代码,能自动创建activiti的表