工作流的使用
1.环境搭建,使用spring boot搭建activiti工作流
先下载插件,画activiti流程图使用,idea中下载插件,点击file-->Settings
2.在项目中引入依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<!-- <dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>7.0.0.Beta1</version>
</dependency>-->
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
创建Activiti配置文件activiti.cfg.xml
<!--数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</bean>
<!--配置Activiti使用的processEngine对象 默认命名为processEngineConfiguration,可以自定义命名,但是需要我们在初始化配置文件的时候加上自定义id 作为参数-->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
<!--配置数据源方式二:-->
<!--<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>-->
<!--指定数据库生成策略,代表是否生成表结构-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
创建类加载配置文件并生成数据表
@Test
public void createProcessEngineWithXMLConfig(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
// .createProcessEngineConfigurationFromResource("activiti.cfg.xml",beanid);
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
System.out.println(processEngine);
}
//另一种加载配置生成数据表的简单写法
//条件:activati配置文件名称默认为:activati.cfg.xml bean的id=processEngineConfiguration
@test
public void testGenTable(){
ProcessEngine processEngine =ProcessEngine.getDefaultProcessEngine();
System.out.println(processEngine);
}
3.流程定义,先将流程图bpmn画好
-
任务的执行人目前指定,填写请假单的assignee为zhangsan,部门经理审批的assignee为lisi
-
将bpmn文件后缀名修改为xml文件然后文件右击选择diagrams导出png图片
4.代码演示
1.流程部署
- 影响的数据表
act_re_deployment 部署信息
act_re_procdef 流程定信息 每个流程都应该有自己唯一的key
act_ge_bytearray 保存上传的资源
@RunWith(SpringRunner.class)
@SpringBootTest
public class test {
@Resource
private ProcessEngine processEngine;
@Test
public void repository() {
//1.创建processEngine对象
//ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.进行部署
Deployment deployment = repositoryService.createDeployment()//创建deploment对象
.addClasspathResource("test.bpmn")//添加资源
.addClasspathResource("test.png")//添加ziyuan
.name("请假单")//流程名字
.deploy();//流程的部署
//4.输出部署的一些信息
System.out.println(deployment.getId());
System.out.println(deployment.getName());
}
- 第二种流程部署的方式,使用压缩包文件部署流程 在上传服务器是需求 zip文件更方便将流程定义bpmn文件跟pngwenjian压缩,压缩文件为zip格式
/**
* 使用压缩包文件部署流程 在上传服务器是需求 zip文件更方便
* 将流程定义bpmn文件跟pngwenjian压缩,压缩文件为zip格式
*/
@Test
public void repositoryByZip() {
//1.创建processEngine对象
//ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.转化出ZipInputStream流对象
InputStream is=this.getClass().getClassLoader().getResourceAsStream("Bpmn.zip");
//转换
ZipInputStream zip=new ZipInputStream(is);
//4.进行部署
Deployment deployment = repositoryService.createDeployment()//创建deploment对象
.addZipInputStream(zip)
.name("请假单")//流程名字
.deploy();//流程的部署
//4.输出部署的一些信息
System.out.println(deployment.getId());
System.out.println(deployment.getName());
}
2.流程的启动
- 影响的表:
act_hi_actinst 流程节点的完成情况 时间记录了节点的开始时间和完成时间
act_hi_identitylink 记录了这个流程的节点参与者信息
act_hi_procinst 流程实例
act_hi_taskinst 任务表 节点任务的详情 任务实例
act_ru_execution 执行表
act_ru_identitylink 流程实例节点需要完成任务的人 参与者信息
act_ru_task 记录实例节点当前是哪一个任务 任务
//流程的启动
@Test
public void ActivitiStartInstance(){
//获取RuntimrService 对象
RuntimeService runtimeService = processEngine.getRuntimeService();
//创建流程实例 流程定义的key 或者别的参数
ProcessInstance myTest = runtimeService.startProcessInstanceByKey("myTest");
//输出实例相关信息
System.out.println(myTest.getBusinessKey());
System.out.println(myTest.getDeploymentId());
}
3.任务列表查看
- 查询的表
ACT_RU_TASK
ACT_RE_PROCDEF
/**
* 查看当前用户的任务列表查询
*/
@Test
public void ActicitiTaskQuery(){
//得到TaskService对象
TaskService taskService = processEngine.getTaskService();
//根据流程定义的key,负责人assignee来实现当前用户的任务列表查询
List<Task> taskList = taskService.createTaskQuery()
.taskAssignee("zhangsan")
.processDefinitionKey("myTest")
.list();
//任务列表展示
for (Task task:taskList) {
System.out.println("流程实例id"+task.getProcessDefinitionId());
System.out.println("任务id"+task.getId());
System.out.println("任务负责人"+task.getAssignee());
System.out.println("任务名称"+task.getName());
}
}
4.完成任务或者说执行任务,zhangsan完成请假单的填写
- 影响的表:
- act_hi_taskinst act_hi_actinst 更新数据 end_time有了记录 并且插入了下一个节点的任务
- act_hi_identitylink 插入了下一个节点的任务参与者
- act_ru_execution 中的实例信息ACT_ID_改成了任务节点的id
- act_ru_identitylink 插入节点任务
- act_ru_task 数据发生更新 更新成下一个节点任务的信息
/**
* 完成任务
*/
@Test
public void ActivitiCompleteTask(){
//得到TaskService对象
TaskService taskService = processEngine.getTaskService();
//得到任务
Task task = taskService.createTaskQuery()
.taskAssignee("zhangsan")
//.processInstanceId(lcid)这里一般使用流程的id去联查
.singleResult();//显示唯一的任务
//根据任务id完成任务
taskService.complete(task.getId());//在实际开发中一般是任务查找跟任务的完成结合一起
}
5. 接下来就是lisi来完成审批任务
- 影响的表
- act_ru_task act_ru_identitylink act_ru_execution 所有任务完成后表里跟这次流程相关的记录没了
- act_hi_taskinst 更新了lisi(最后完成任务的人)的完成时间 end_time
- act_hi_identitylink 由于是最后环节了 所有没有变化
- act_hi_actinst 更新了lisi(最后完成任务的人)的完成时间 end_time
/**
*接下来就是lisi来完成审批任务
*/
@Test
public void ActivitiCompleteTask1(){
//得到TaskService对象
TaskService taskService = processEngine.getTaskService();
//得到任务
Task task = taskService.createTaskQuery()
.taskAssignee("lisi")
//.processInstanceId(lcid)这里一般使用流程的id去联查 或者 key
.singleResult();
//根据任务id完成任务
taskService.complete(task.getId());
}
6.总结
1.BPMN 的流程定义
2.idea中画出流程定义
3.ProcessEngineConfiguration 类 作用:加载activiti.cfg.xml 配置文件
4.ProcessEngine类 作用 帮助我们获得 各个Service 接口 并且生成工作环境(25张表的生成)
5.Service 接口 作用 帮助我们方便快速的操作数据库相关的表
- 部署流程定义
- 方式一:单个文件(bpmn文件,png文件)
- 方式二:压缩包的方式(先将bpmn 文件和png文件压缩成zip文件)
- 启动流程实例:RuntimeService startProcessInstanceByKey(“key”)
- 查看任务:TaskService taskService.createTaskQuery()
- 完成任务:TaskService taskService.complete()//参数为任务id
7.扩展使用
- 流程定义的查询
/**
* 流程定义的查询
* */
@Test
public void queryProcessDefinition() {
//得到RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService();
//得到ProcessDefinitionQuery对象, 可以任务是一个查询器
ProcessDefinitionQuery processDefinitionQuery =repositoryService.createProcessDefinitionQuery();
//设置条件并查询出当前所有的流程定义 查询条件:流程定义的key
List<ProcessDefinition> list= processDefinitionQuery.processDefinitionKey("myTest")
.orderByProcessDefinitionVersion() //通过版本号排序
.desc().list();//降序
//输出流程定义的信息
for (ProcessDefinition processDefinition:list) {
System.out.println("流程定义ID:"+processDefinition.getId());
System.out.println("流程定义名称:"+processDefinition.getName());
System.out.println("流程定义key:"+processDefinition.getKey());
System.out.println("流程定义版本号:"+processDefinition.getVersion());
// 流程定义ID:myTest:1:90004
// 流程定义名称:请假单
// 流程定义key:myTest
// 流程定义版本号:1
}
}
- 删除已经部署的流程定义
注意事项:当我们正在执行的这一套流程没有完全审批结束的时候,此时删除流程定义信息会失败,我们可以使用级联删除--> repositoryService.deleteDeployment("90001",true);//true 级联删除 此时会先删除还没有完成的流程节点,最后就可以删除流程定义的信息
/**
* 删除已经部署的流程定义
*/
@Test
public void deleteProcessDefinition() {
//得到RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService();
//得到ProcessDefinitionQuery对象, 可以任务是一个查询器
ProcessDefinitionQuery processDefinitionQuery =repositoryService.createProcessDefinitionQuery();
//设置条件并查询出当前所有的流程定义 查询条件:流程定义的key
List<ProcessDefinition> list= processDefinitionQuery.processDefinitionKey("myTest")
.orderByProcessDefinitionVersion() //通过版本号排序
.desc().list();//降序
//输出流程定义的信息
for (ProcessDefinition processDefinition:list) {
System.out.println("流程定义ID:"+processDefinition.getId());
System.out.println("流程定义名称:"+processDefinition.getName());
System.out.println("流程定义key:"+processDefinition.getKey());
System.out.println("流程定义版本号:"+processDefinition.getVersion());
System.out.println("流程定义部署id:"+processDefinition.getDeploymentId());
// 流程定义ID:myTest:1:90004
// 流程定义名称:请假单
// 流程定义key:myTest
// 流程定义版本号:1
// 流程定义部署id:90001
//删除操作 参数流程部署的id
repositoryService.deleteDeployment("90001");
//注意事项,当我们正在执行的这一套流程没有完全审批结束的时候,此时删除流程定义信息会失败
//若想删除 加一个参数 true 表示强制删除
repositoryService.deleteDeployment("90001",true);//true 级联删除 此时会先删除还没有完成的流程节点,最后就可以删除流程定义的信息
}
}
- 从Activiti的act_ge_bytearray 表中读取两个资源文件
将两个文件保存到路径为:D:
应用场景:因为当客户想查看我们的流程具体有哪些步骤的时候我们需要获取png文件就可以清楚了解流程的步骤
/**
* 从Activiti的act_ge_bytearray 表中读取两个资源文件
*/
@Test
public void queryBpmnFile(){
//得到RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService();
//得到ProcessDefinitionQuery对象, 可以任务是一个查询器
ProcessDefinitionQuery processDefinitionQuery =repositoryService.createProcessDefinitionQuery();
//查询条件
processDefinitionQuery.processDefinitionKey("myTest");
//执行查询操作,查询出想要的流程定义
ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
//通过流程定义信息,得到部署id
String deploymentId = processDefinition.getDeploymentId();
//通过repositoryService的方法,实现读取图片信息以及bpmn文件信息(输入流)
//getResourceAsStream()方法参数说明:第一个是部署id,第二个是资源名称
//processDefinition.getDiagramResourceName() 代表获取png图片资源的名称
//processDefinition.getResourceName() 代表获取bpmn文件的名称
InputStream pngip=repositoryService.getResourceAsStream(deploymentId,processDefinition.getDiagramResourceName());
InputStream bpmnip=repositoryService.getResourceAsStream(deploymentId,processDefinition.getResourceName());
OutputStream pngos=null;
OutputStream bpmnos=null;
//构建出OutputStream流
try {
pngos=new FileOutputStream("D:\\"+processDefinition.getDiagramResourceName());
bpmnos=new FileOutputStream("D:\\"+processDefinition.getResourceName());
//输入流,输出流转换
byte[] b=new byte[1024];
int len=-1;
while ((len=pngip.read(b,0,1024))!=-1){
pngos.write(b,0,len);
}
while ((len=bpmnip.read(b,0,1024))!=-1){
bpmnos.write(b,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//关闭流
pngos.close();
bpmnos.close();
pngip.close();
bpmnip.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 查询历史记录
/**
* 查询历史记录
*/
@Test
public void historyQuery(){
//得到HistoryService对象
HistoryService historyService = processEngine.getHistoryService();
//得到HistoryActivitiInstanceQuery 对象 查询器
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
//设置流程实例id
historicActivityInstanceQuery.processInstanceId("92501");
//执行查询
List<HistoricActivityInstance> list = historicActivityInstanceQuery.list();
//遍历结果集
for (HistoricActivityInstance his:list) {
System.out.println("节点id:"+his.getActivityId());
System.out.println("节点任务名称:"+his.getActivityName());
System.out.println("流程定义id:"+his.getProcessDefinitionId());
System.out.println("实例id:"+his.getProcessInstanceId());
// 节点id:_2
// 节点任务名称:StartEvent
// 流程定义id:myTest:1:90004
// 实例id:92501
// 节点id:_3
// 节点任务名称:填写请假单
// 流程定义id:myTest:1:90004
// 实例id:92501
// 节点id:_4
// 节点任务名称:部门经理审批
// 流程定义id:myTest:1:90004
// 实例id:92501
// 节点id:_5
// 节点任务名称:EndEvent
// 流程定义id:myTest:1:90004
// 实例id:92501
}
}
}
- 流程的挂起与激活
挂起状态 该流程下的所有流程实例全部暂停,也不允许启动新的流程
/**
* 流程的挂起与激活
* 挂起状态 该流程下的所有流程实例全部暂停,也不允许启动新的流程
*/
@Test
public void SuspendProcessInstance(){
//得到RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//查询流程定义对象
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myTest").singleResult();//通过流程key
//获取流程状态
boolean suspended = processDefinition.isSuspended();
//获取流程id
String processDefinitionId = processDefinition.getId();
//判断
if (suspended){
//说明是暂停了,可以进行激活操作
repositoryService.activateProcessDefinitionById(processDefinitionId,true,null);
}else{
//暂停操作
repositoryService.activateProcessDefinitionById(processDefinitionId,true,null);
}
}
- 单个实例的挂起和激活
/**
* 单个实例的挂起和激活
*/
@Test
public void SuspendProcessInstance1(){
//得到RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//查询流程定义对象
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processDefinitionKey("myTest").singleResult();//通过流程key
//获取流程状态
boolean suspended = processInstance.isSuspended();
//获取流程id
String processInstanceId = processInstance.getId();
//判断
if (suspended){
//说明是暂停了,可以进行激活操作
runtimeService.activateProcessInstanceById(processInstanceId);
}else{
//暂停操作
runtimeService.suspendProcessInstanceById(processInstanceId);
}
}