用activiti 工作流 实现简单的请假 / SSM整合Activiti工作流

新建一个Maven项目

项目结构

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
 
	<groupId>com.dengkun.activiti</groupId>
  <artifactId>Test1</artifactId>
  <version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>Test1Name</name>
  <description>Test1d</description>
 
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
 
	<dependencies>
		<dependency>
		  <groupId>org.vaadin.addons</groupId>
		  <artifactId>dcharts-widget</artifactId>
		  <version>0.10.0</version>
		  <type>jar</type>
		</dependency>
		<!-- Activiti -->
		<dependency>
			<groupId>org.activiti</groupId>
			<artifactId>activiti-engine</artifactId>
			<version>5.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.activiti</groupId>
			<artifactId>activiti-spring</artifactId>
			<version>5.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.activiti</groupId>
			<artifactId>activiti-explorer</artifactId>
			<version>5.15.1</version>
		</dependency>
		<!-- Database -->
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.29</version>
		</dependency>
		<!-- spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>4.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>4.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>4.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>4.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>4.0.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>4.0.6.RELEASE</version>
		</dependency>
		<!-- mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.2.5</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.2.2</version>
		</dependency>
		<!-- junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
		</dependency>
		<!-- log -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.4</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.6</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>1.7.6</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.6</version>
		</dependency>
		<!-- commons -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.1</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.4</version>
		</dependency>
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.2.2</version>
		</dependency>
		<!-- other -->
		<dependency>
			<groupId>javax.annotation</groupId>
			<artifactId>javax.annotation-api</artifactId>
			<version>1.2</version>
		</dependency>
		<dependency>
			<groupId>joda-time</groupId>
			<artifactId>joda-time</artifactId>
			<version>2.1</version>
		</dependency>
		
	</dependencies>
</project>

activiti.cfg.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
		<property name="jdbcUrl" value="jdbc:mysql:///myactiviti" />
		<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUsername" value="root" />
		<property name="jdbcPassword" value="123456" />
		<property name="databaseSchemaUpdate" value="true" />
	</bean>
</beans>

 在 resource 下新建Activiti Diagram

将UserTask分别修改成入下图所示

 修改好ID 和 NAME然后在修改Main config中的Assignee,员工请假修改为张三,老板审批修改为老板

点击Window--->Preferences--->Activiti--->Save Actions:将Create process definition image when saving the diagram勾选

然后保存bpmn文件的时候会自动帮你截图

通过ProcessEngines.getDefaultProcessEngine获取流程引擎

注:请先在MySql建立数据库myactiviti,使用默认设置即可,然后运行App.java 中的main函数,当获取到的processEngine对象不为空时   就会在数据库创建关于activiti的23张表,要保证数据库连接正常。

public class App {
	public static void main(String[] arg){
		ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 
	}
}

 通过源码可以看到  getDefaultProcessEngine方法会通过默认的activiti.cfg.xml文件名或者是activiti-context.xml文件名读取xml文件

具体作用如下:

 

 

跟详细的情况可以去下面这个地址了解:

http://www.cnblogs.com/llzgzljl/archive/2013/10/07/3356108.html

此时你可以在数据库中看到act_ge_property表中插入了3条数据

将MyLeave.bpmn和MyLeave.png打包成myleave.zip文件(一定要是zip别压缩成rar)

执行以下方法,发布请假流程:

MyTest.java

附录的项目的代码,建议执行一个函数看下数据库再执行下一个,能比较快速上手数据库。

注:保证数据库链接正常,否则processEngine会报空指针。

	/**
	 * 发布流程
	 * 发布流程后,流程文件会保存到数据库中
	 */
	@Test
	public void deployFlow(){
		RepositoryService repositoryService = processEngine.getRepositoryService();
		
		//获取在classpath下的流程文件
		InputStream in = this.getClass().getClassLoader().getResourceAsStream("myleave.zip");
		ZipInputStream zipInputStream = new ZipInputStream(in);
		//使用deploy方法发布流程
		repositoryService.createDeployment()
						 .addZipInputStream(zipInputStream)
						 .name("Myleave")
						 .deploy();
	}

查看数据库  发布的流程文件信息会保存在下面的三张表中:

 我们可以通过RepositoryService获取详细的流程定义信息

	@Test
	public void queryProcdef(){
		RepositoryService repositoryService = processEngine.getRepositoryService();
		//创建查询对象
		ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
		//添加查询条件
		query.processDefinitionKey("myProcess");//通过key获取
			// .processDefinitionName("My process")//通过name获取
			// .orderByProcessDefinitionId()//根据ID排序
		//执行查询获取流程定义明细
		List<ProcessDefinition> pds = query.list();
		for (ProcessDefinition pd : pds) {
			System.out.println("ID:"+pd.getId()+",NAME:"+pd.getName()+",KEY:"+pd.getKey()+",VERSION:"+pd.getVersion()+",RESOURCE_NAME:"+pd.getResourceName()+",DGRM_RESOURCE_NAME:"+pd.getDiagramResourceName());
		}
	}

key 和 name 就是我们原先画bpmn时候声明的:

使用流程定义的Key发布一个请假流程

/**
	 * 发布流程
	 */
	@Test
	public void startFlow(){
		
		RuntimeService runtimeService = processEngine.getRuntimeService();
		/**
		 * 启动请假单流程  并获取流程实例
		 * 因为该请假单流程可以会启动多个所以每启动一个请假单流程都会在数据库中插入一条新版本的流程数据
		 * 通过key启动的流程就是当前key下最新版本的流程
		 * 
		 */
		ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");
		System.out.println("id:"+processInstance.getId()+",activitiId:"+processInstance.getActivityId());
	}

 

流程发布后在  act_ru_task ,act_ru_execution, act_ru_identitylink 表中插入流程数据

接下来就可以通过用户ID去查看该用户的任务了

	/**
	 * 查看任务
	 */
	@Test
	public void queryTask(){
		//获取任务服务对象
		TaskService taskService = processEngine.getTaskService();
		//根据接受人获取该用户的任务
		List<Task> tasks = taskService.createTaskQuery()
									.taskAssignee("张三")
									.list();
		for (Task task : tasks) {
			System.out.println("ID:"+task.getId()+",姓名:"+task.getName()+",接收人:"+task.getAssignee()+",开始时间:"+task.getCreateTime());
		}
	}

 提出请假申请,启动流程

	@Test
	public void startTask(){
		TaskService taskService = processEngine.getTaskService();
		//taskId 就是查询任务中的 ID
		String taskId = "204";
		//完成请假申请任务
		taskService.complete(taskId );
	}

查看数据库变化 可以看到 表中的数据已经变成了老板审批相关数据

老板查看任务 ,并审批请假

	/**
	 * 查看任务
	 */
	@Test
	public void queryTask(){
		//获取任务服务对象
		TaskService taskService = processEngine.getTaskService();
		//根据接受人获取该用户的任务
		List<Task> tasks = taskService.createTaskQuery()
									.taskAssignee("老板")
									.list();
		for (Task task : tasks) {
			System.out.println("ID:"+task.getId()+",姓名:"+task.getName()+",接收人:"+task.getAssignee()+",开始时间:"+task.getCreateTime());
		}
	}
	@Test
	public void startTask(){
		TaskService taskService = processEngine.getTaskService();
		//taskId 就是查询任务中的 ID
		String taskId = "302";
		//完成请假申请任务
		taskService.complete(taskId );
	}

 流程完毕,可以再act_hi_actinst表中看到整个请假流程

 

整个流程的过程是  1.发布流程 --->2.启动流程--->3.相关人查看任务完成并完成

数据都是存放在数据库中

 

具体详情可以查看Activiti 用户手册

http://www.mossle.com/docs/activiti/#

 

博文原址为:http://blog.csdn.net/a67474506/article/details/38266129感谢原博主的博文,让我3个小时就搞明白,之前看了陆陆续续看了几个月的说明书,还是没有入门,看此文让我顿时明悟。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

SSM整合Activiti

在工作流中,我们一切工作流的基本就是工作引擎(ProcessEngine),继承于EngineService接口,包括流程部署,数据库连接都是靠着ProcessEngine来实现的。而ProcessEngineConfiguration:流程引擎配置,可以设置数据库等,默认的数据库是h2,持久化实现使用的Mybatis,这里我们用的是MySQL

       那么既然无论是jbpm或者是activiti都需要ProcessEngine来驱动,那么我们就说一下工作流引擎的使用吧。

       流程部署

       当我们将我们的业务画成图的时候,然后利用工作流引擎部署,也就是将我们的流程图信息放到数据库,图和代码如下:

 

/**部署流程定义*/
	@Test
	public void deploymentProcessDefinition(){
		Deployment deployment = processEngine.getRepositoryService()  //用于流程定义和部署相关对象的Service
						.createDeployment()   //创建一个部署对象
						.name("leaveBill部门程序")
						.addClasspathResource("diagrams/LeaveBill.bpmn") //从ClassPath资源中加载,一次只能加载一个文件
						.addClasspathResource("diagrams/LeaveBill.png")  //从ClassPath资源中加载,一次只能加载一个文件
						.deploy();
		
		System.out.println("deployment" + deployment.getId());   //1
		System.out.println("deployment" + deployment.getName());//部门程序
	
	}

打印结果如下:

 

      deployment1
      deploymenthellworld部门程序

      数据库(部署相关表)解析

      我们看一下数据库的表会发现,每次部署都是涉及的那三张表,act_re_deployment(流程部署表)

    该表包含了流程部署的名称,ID,和部署时间

act_re_procdef(流程定义表)

该表有流程定义的主键key,版本(version)源文件名和图示,还有流程定义ID(key + 版本号+随机生成的数字)

act_ge_bytearray(资源文件表)

 保存了资源的位置和存储方式和部署ID,版本号ID等信息

      act_ge_property:主键生成策略表

 定义了主键生成的策略信息

 执行流程

        顾名思义,就是当我们有一个人开始申请请假的时候我们就要执行该请假的流程实例了

	/**
	 * 执行流程实例
	 */
	@Test
	public void startProcessInstance(){
		String processInstanceKey = "LeaveBill";
		ProcessInstance pi = processEngine.getRuntimeService()
							.startProcessInstanceByKey(processInstanceKey);
		System.out.println("流程实例id:" + pi.getId());  //流程实例id  101
		System.out.println("流程定义id:" + pi.getProcessDefinitionId());   //流程定义ID helloworld:1:4
	}

        这样我们的流程实例就启动起来了,那么接下来我们看一下在启动流程实例的时候我们涉及到的表信息

      数据库分析(实例表)分析

act_ru_execution: 正在执行的执行对象表,侧重流程实例,对象,任务

 

包含了实例ID,流程定义ID,要执行的任务名称(usertask1)等信息

       act_ru_task:正在执行的任务表,对具体的任务而言,任务执行到哪里了

 act_ru_identitylink流程信息变量act_hi_taskinst:已经执行完的历史任务信息

act_hi_taskinst:已经执行完的历史任务信息
act_hi_procinst:流程实例的历史表,存放执行完毕的流程实例信息

act_hi_actinst:存放历史所有完成的活动

           现在我们对表有一个大致的了解,那么接下来我们就按照我们既定的流程去执行我们的请假,例如第一个项目经理叫张三,那么这个流程实例已启动,首先需要张三去执行操作,那么我们我们看一下张三的执行任务的详情,代码如下:

/**
	 * 查找个人当前的要执行的任务
	 */
	@Test
	public void findMyTaskInfo(){
		String assignee = "张三";
		List<Task> listTask = processEngine.getTaskService()
			.createTaskQuery()
			.taskAssignee(assignee)
			.list();
		
		if (listTask!= null && listTask.size() >0) {
			for (Task task : listTask) {
				System.out.println("任务ID:" + task.getId());
				System.out.println("任务名称:" + task.getName());
				System.out.println("任务时间:" + task.getCreateTime());
				System.out.println("任务的班里人:" + task.getAssignee());
				System.out.println("任务的实例ID:" + task.getProcessDefinitionId());
				System.out.println("执行对象的ID:" + task.getExecutionId());
				System.out.println("任务的班里人:" + task.getAssignee());
				System.out.println("流程定义ID:" + task.getProcessInstanceId());
			}
		}
			
		
	}

      打印信息如下:任务ID:304,任务名称:【项目经理】审批,任务时间:Sat Jan 23 14:54:35 CST 2016,任务的班里人:张三 任务的实例ID:LeaveBill:2:204     执行对象的ID:301   任务的班里人:张三  流程定义ID:301

       任务完成

        那么接下来我就把任务ID为304的一个流程结束,也就是项目经理同意请假,代码如下:

	/**完成任务*/
	@Test
	public void completeMyPersoinTask() {
		String taskId = "304";
		processEngine.getTaskService()
		.complete(taskId);
		
		System.out.println("完成任务,任务ID:" + taskId);
	}

       然后我继续执行查询个人任务的时候,我们只能查到主任的任务了,因为项目经理已经执行完毕,所以当前执行的任务是看不到的,但是在历史信息中是存在的。

       如果我们启动了实例的话,查询当前信息的话,实在act_ru_*的表中查询,根据任务有关的服务,都是taskService,当然Activiti还有很多的服务,例如RepositoryService,RuntimeService, HistoryService等服务。

      大致总结一下,就是先部署,再启动,个人登陆系统后,根据个人姓名,查到任务ID,完成个人任务,直到全部完成,就是这么简单。

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

学完Activiti所有的知识点了,现在可以用一个小项目实战一下。

本来自己想写一个简单点的流程,但是发现项目太小有些知识点用不上,所有就写了一个流程比较长、复杂点。

把我前面博客中写的知识点多用上了,也巩固一下前面所掌握的。

 

 通过

首先介绍一下项目的流程:

1.员工发起请假申请——>项目组长进行初步审批——>就进入 并行网关 未通过就直接结束流程

2.并行网关 :需要相关的节点多同意才进入下一步流程

3.这一步就需要:项目经理、项目总监审批通过才进入下一步,其中如果有一个人不同意及流程结束。

4. 到了人事部处理审批——>到了排他网关 :是对条件进行判断然后在进入对应的审批人

5.注意点:并行网关:是相关审批人多同意才进入一下步。(外观是个 “ +” 号)

   排他网关:是根据已给条件进行判断,然后在进入对应审批人。(外观是插号)

6.根据请假天数判断是谁审批———>最后结束流程

先展示一下项目效果吧:

用户登入界面:选择员工角色登入

 员工角色:有基本的系统管理、请假申请等功能。

开始发起请假申请:

点击确定:

 

然后提交请假申请,状态发生了改变。

 

 跟着流程走,接着切换项目组长审批:(测试的时候确定一个人切换账号巨麻烦)

 

点击任务管理——>待办任务:就有刚才发起的请假申请

 

 

点击办理任务:

 

然后填写批注:可以随便写点什么——>点击批注(同意)或者是驳回(不同意)

 

 之后可以点击任务管理————>已办任务查看:

 

这就是刚才审批的请假任务,多可以点击:

查看历史批注:

 

查看流程执行过程:

 

以及任务管理————>历史任务查看:

 

然后切换账号为项目经理登入,审批请假任务:

还是一样的操作:

 

我就不一个个截图试了。

并行网关,这就需要项目经理、项目总监多同意审批才能接着下去。

请假任务现在执行到项目经理、项目总监审批,如果你用人事、总裁等账号登入:

因为请假流程还没有执行到那一步,所以没有任务。

 

我就跳过中间步骤:现在是人事部处理

 

现在是进入:排他网关判断请假天数,大于等于7天是总裁审批,小于7天是副总裁审批。

这里请假天数是10天,现在使用副总裁的角色登入系统看看:

 

没有待办任务,说明正确的执行了排他网关。

好接着使用总裁角色登入系统结束任务:

 

 

现在流程正常走完了,如果在中间有任何一个角色审批不同意流程当立即结束。

在回到张三这个员工登入系统看看:

 

 

请假流程基本就结束了,接着使用管理员角色登入系统:

 

管理员角色:基础数据管理模块 

1.用户管理,批量删除用户,新增、修改用户等等。

2.角色管理,批量删除角色,新增、修改角色等等。

3.角色权限管理,赋予用户角色,每个用户可以拥有多个角色,

删除用户角色等等。

 

流程管理模块:流程部署管理(就是流程图管理)

1.以ZIP压缩包的形式添加流程图

2.批量删除流程

 

流程定义管理:

1.一些新增、修改、查询等等。

2.查看流程图

 

 

下面还有一些功能就不说了,重点还是Activiti工作流嘛。

https://blog.csdn.net/u011277123/article/details/77081860

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值