关闭

工作流引擎Activiti系列(一)——初识

标签: activiti工作流引擎
5434人阅读 评论(1) 收藏 举报
分类:

1、介绍

    几乎任何一个公司的软件开发都会涉及到流程,以往我们可能是这么实现的:业务表添加标志位标识流程的节点状态,关联批注表实现审核意见,根据一些业务数据分析处理逻辑,分配任务到用户,节点的调度,审批等.....这其实是很繁琐的,且不说开发起来比较混乱,维护起来更是难上加难:

    

    Activiti刚好就能解决几乎所有的这些问题,当流程开发变得简单有趣。

    官网:https://www.activiti.org/

    官方文档:https://www.activiti.org/userguide/

    Activiti项目是一项新的基于Apache许可的开源BPM平台,从基础开始构建,旨在提供支持新的BPMN 2.0标准,包括支持对象管理组(OMG),面对新技术的机遇,诸如互操作性和云架构,提供技术实现。

    作为开发者,使用Activiti带给我的直接好处:

  1.     天然支持Spring(Spring需要在配置文件中自己定义Activiti的Bean,Spring Boot则不需要)
  2.     流程定义通过画流程图实现(官方提供了相关工具,Eclipse也有插件支持),简单直观,易维护,易修改。
  3.     审批条件参数化,流程分支简单实现。
  4.     审批人可使用多种方式设置(支持用户、用户组、角色、候选组以及监听器动态设置),灵活,简单。
  5.     统一的审批接口,并不需要判断流程当前节点和走向。
  6.     提供强大的JPA查询,同时支持Name Query和Native Query。
  7.     流程数据与业务数据分离。

    后续文章会一步步介绍Activiti的功能,主要使用基于Spring Boot的工程,也会提供单纯的Spring工程Demo。

2、示例

    此处演示一个小示例,暂不解释代码,仅仅看看是怎样用activiti实现的。

    场景就是请假,不过这里稍稍多了点内容,就是请假由请假人对应部门的领导审批,而不是统一的某一部分人。

    2.1、使用Spring Boot工程

    首先创建Spring boot工程,为了演示方便,使用内存数据库,完整pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<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.anxpp</groupId>
	<artifactId>ActivitiDemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>ActivitiDemo</name>
	<description>ActivitiDemo</description>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.3.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<!-- <dependency> -->
		<!-- <groupId>org.mybatis.spring.boot</groupId> -->
		<!-- <artifactId>mybatis-spring-boot-starter</artifactId> -->
		<!-- <version>1.1.1</version> -->
		<!-- </dependency> -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.activiti</groupId>
			<artifactId>spring-boot-starter-basic</artifactId>
			<version>5.17.0</version>
		</dependency>
		<!-- 内存数据库  -->
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
		</dependency>
		<!-- <dependency> -->
		<!-- <groupId>mysql</groupId> -->
		<!-- <artifactId>mysql-connector-java</artifactId> -->
		<!-- <scope>runtime</scope> -->
		<!-- </dependency> -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
	<distributionManagement>
		<repository>
			<id>Releases</id>
			<name>Nexus Release Repository</name>
			<url>http://anxpp.com/nexus/content/repositories/releases/</url>
		</repository>
		<snapshotRepository>
			<id>Snapshots</id>
			<name>Nexus Snapshot Repository</name>
			<url>http://anxpp.com/nexus/content/repositories/snapshots/</url>
		</snapshotRepository>
	</distributionManagement>
	<repositories>
		<repository>
			<id>nexus</id>
			<name>Nexus</name>
			<url>http://anxpp.com/nexus/content/groups/public/</url>
			<layout>default</layout>
			<releases>
				<enabled>true</enabled>
			</releases>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
	</repositories>
</project>

    2.2、流程定义

    这里使用eclipse的activiti designer插件,插件安装方法另见:Eclipse安装Activiti Designer插件

    如我所愿,这里以请假流程,使用流程设计器得到如下流程定义:

    流程定义

    这个流程相当简单。下面是定义的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="myProcess" name="My process" isExecutable="true">
    <extensionElements>
      <activiti:executionListener event="end" class="com.anxpp.demo.activiti.simple.listener.SimpleProcessEndListener"></activiti:executionListener>
    </extensionElements>
    <startEvent id="startevent_simple" name="Start"></startEvent>
    <userTask id="usertask1" name="领导审批">
      <extensionElements>
        <activiti:taskListener event="create" class="com.anxpp.demo.activiti.simple.listener.LeaderCheckListener"></activiti:taskListener>
      </extensionElements>
    </userTask>
    <endEvent id="endevent_simple" name="End"></endEvent>
    <sequenceFlow id="flow_toCheck" sourceRef="startevent_simple" targetRef="usertask_leadercheck"></sequenceFlow>
    <sequenceFlow id="flow_toEnd" sourceRef="usertask_leadercheck" targetRef="endevent_simple"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
    <bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
      <bpmndi:BPMNShape bpmnElement="startevent_simple" id="BPMNShape_startevent_simple">
        <omgdc:Bounds height="35.0" width="35.0" x="170.0" y="290.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="290.0" y="280.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent_simple" id="BPMNShape_endevent_simple">
        <omgdc:Bounds height="35.0" width="35.0" x="500.0" y="290.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

    里面包含一个用户任务、一个流程监听器(流程结束后回写业务数据状态)、一个任务监听器(以为审批是由申请员工对应部门的领导审核的,使用监听器可以灵活的设置任务审批候选人)。

    2.3、监听器

    监听器分任务监听器和流程监听器。

    任务监听器

/**
 * 领导审核监听器
 * @author anxpp.com
 * 2016年12月24日 下午12:10:01
 */
public class LeaderCheckListener implements TaskListener{
	private static final long serialVersionUID = 4285398130708457006L;
	private final static Logger log = LoggerFactory.getLogger(LeaderCheckListener.class);
	@Override
	public void notify(DelegateTask task) {
		log.info("领导审核监听器...");
		//设置任务处理候选人
		UserService userService = SpringUtil.getBean(UserService.class);
		List<String> leaders = userService.getSimpleCheckerByDept(Long.valueOf(task.getVariable("dept").toString()));
		log.info(leaders.toString());
		log.info(task.getVariable("dept").toString());
		task.addCandidateUsers(leaders);
	}
}

 流程监听器(此处并无实际代码,只给写法):

/**
 * 流程监听器
 * @author anxpp.com
 * 2016年12月24日 下午12:33:58
 */
public class SimpleProcessEndListener implements ExecutionListener{
	private static final long serialVersionUID = 5212042435691138021L;
	private final static Logger log = LoggerFactory.getLogger(SimpleProcessEndListener.class);
	@Override
	public void notify(DelegateExecution arg0) throws Exception {
		log.info("流程结束监听器...");
		//TODO 修改业务数据状态
	}
}

    单元测试

package com.anxpp.demo.activiti;
import java.util.Iterator;
import java.util.List;
import org.activiti.engine.task.Task;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.anxpp.demo.activiti.core.entity.User;
import com.anxpp.demo.activiti.core.service.UserService;
import com.anxpp.demo.activiti.simple.Config.Constant;
import com.anxpp.demo.activiti.simple.core.entity.ApplySimple;
import com.anxpp.demo.activiti.simple.core.service.ApplySimpleService;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ActivitiDemoApplicationTests {
	private final static Logger log = LoggerFactory.getLogger(ActivitiDemoApplicationTests.class);
	private static Long DEPT_TINY_SOFTWARE_STUDIO = 1L;
	private static Long DEPT_OTHER = 2L;
	@Autowired
	UserService userService;
	@Autowired
	ApplySimpleService simpleService;
	/**
	 * 测试程序启动
	 */
	@Test
	public void contextLoads() {
	}
	/**
	 * 测试数据库操作
	 */
	@Test
	public void testCURD(){
		Long countUser = userService.countUser();
		User user = new User();
		user.setName("anxpp0");
		user.setDept(DEPT_TINY_SOFTWARE_STUDIO);
		userService.save(user);
		Assert.assertEquals(new Long(countUser+1), userService.countUser());
	}
	/**
	 * 测试简单流程
	 */
	@Test
	public void testSimpleActiviti(){
		long startAt = System.currentTimeMillis();
		//添加申请用户
		User user = new User();
		user.setName("anxpp");
		user.setDept(DEPT_TINY_SOFTWARE_STUDIO);
		user.setPosition(Constant.POSITION_GENERAL);
		userService.save(user);
		//添加审核用户
		User userLeader1 = new User();
		userLeader1.setName("anxpp1");
		userLeader1.setDept(DEPT_TINY_SOFTWARE_STUDIO);
		userLeader1.setPosition(Constant.POSITION_LEADER);
		userService.save(userLeader1);
		User userLeader2 = new User();
		userLeader2.setName("anxpp2");
		userLeader2.setDept(DEPT_OTHER);
		userLeader2.setPosition(Constant.POSITION_LEADER);
		userService.save(userLeader2);
		Long countHis = simpleService.countProcess();
		Long countLeader1Task = simpleService.countTask(userLeader1.getId());
		Long countLeader2Task = simpleService.countTask(userLeader2.getId());
		//创建请假申请
		ApplySimple applySimple = new ApplySimple();
		applySimple.setInsertBy(user.getId());
		applySimple.setComtent("有事请假...");
		//启动请假流程
		simpleService.startProcess(applySimple);
		/**断言历史流程+1*/
		Assert.assertEquals(simpleService.countProcess(), new Long(countHis+1));
		/**断言领导任务变化*/
		Assert.assertEquals(simpleService.countTask(userLeader1.getId()), new Long(countLeader1Task+1));
		Assert.assertEquals(countLeader2Task, simpleService.countTask(userLeader2.getId()));
		//获取用户任务
		List<Task> taskUserLeader1 = simpleService.getTaskByUid(userLeader1.getId());
		//处理任务
		Iterator<Task> iterator = taskUserLeader1.iterator();
		while(iterator.hasNext()){
			Task task = iterator.next();
			/**断言任务节点名称*/
			Assert.assertEquals("领导审批", task.getName());
			simpleService.completeSimpleCheck(task.getId(), ApplySimpleService.STATE_PASS);
		}
		/**断言领导任务变化*/
		Assert.assertEquals(countLeader1Task, simpleService.countTask(userLeader1.getId()));
		Assert.assertEquals(countLeader2Task, simpleService.countTask(userLeader2.getId()));
		System.err.println("asdf");
		log.info("测试完成,花费时间:"+(System.currentTimeMillis()-startAt));
	}
}

    运行单元测试,OK!通过!

    完整实例源码地址:https://github.com/anxpp/activitiSimpleDemo.git

0
1
查看评论

Activiti初学者教程

1. 初识Activiti 1.1. 工作流与工作流引擎 工作流(workflow)就是工作流程的计算模型,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的模型进行表示并对其实施计算。它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从...
  • bluejoe2000
  • bluejoe2000
  • 2014-09-24 11:45
  • 206062

Activiti工作流引擎使用详解

Activiti工作流引擎使用 1.简单介工作流引擎与Activiti 对于工作流引擎的解释请参考百度百科:工作流引擎 1.1 我与工作流引擎 在第一家公司工作的时候主要任务就是开发OA系统,当然基本都是有工作流的支持,不过当时使用的工作流引擎是公司一些牛人开发的(据...
  • m0_37327416
  • m0_37327416
  • 2017-05-12 16:01
  • 2570

【Activiti工作流】3.准备Activiti开发环境

一、准备环境 1.activiti软件环境 1)JDK1.6或者更高版本 2)支持的数据库有:h2, mysql, oracle, postgres, mysql, db2等。 3)支持activiti5运行的jar包 4)开发环境为Eclipse3.7或者以上版本,myeclipse为8.6...
  • u013517797
  • u013517797
  • 2017-02-24 16:42
  • 6379

SSM整合Activiti工作流

学完Activiti所有的知识点了,现在可以用一个小项目实战一下。 本来自己想写一个简单点的流程,但是发现项目太小有些知识点用不上,所有就写了一个流程比较长、复杂点。 把我前面博客中写的知识点多用上了,也巩固一下前面所掌握的。  通过 首先介绍一下项目的流程:1.员工发起请假申请——&...
  • lifupingcn
  • lifupingcn
  • 2017-03-16 16:35
  • 8747

工作流学习——Activiti整体认识二步曲

我们本篇文章主要讲述了activiti的环境准备包含各个软件的版本和安装流程设计器,接下来我们讲解了两种方式来创建activiti的23张表,还夹杂着一个数据库连接url的写法,接下来是activiti核心对象ProcessEngine,以及通过ProcessEngine获取相关的Service,最...
  • zwk626542417
  • zwk626542417
  • 2015-06-22 17:47
  • 19433

Activiti工作流

转载自:http://blog.csdn.net/bluejoe2000/article/details/39521405 1. 初识Activiti 1.1. 工作流与工作流引擎 工作流(workflow)就是工作流程的计算模型,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机...
  • JavaMk
  • JavaMk
  • 2016-05-26 15:36
  • 3162

Activiti工作流框架学习笔记(一)

工作流的概念先看下面两张图: 对以上两张图进行说明: 假设这两张图就是华谊兄弟的请假流程图 图的组成部分: 人物:范冰冰、冯小刚、王中军 事件(动作):请假、批准、不批准 通过以上分析我们就可以抽象成: 接下来给出工作流的书面化概念: 工作流(Workflow),就是“业务过程的部...
  • yerenyuan_pku
  • yerenyuan_pku
  • 2017-05-07 00:52
  • 2563

Activiti工作流demo

继上篇《Activiti工作流的环境配置》        前几篇对Activiti工作流进行了介绍,并讲解了其环境配置。本篇将会用一个demo来展示Activiti工作流具体的体现,直接上干货。 一、demo业务分析  ...
  • u013037201
  • u013037201
  • 2016-09-02 23:06
  • 10353

activiti 工作流会签 / 多人审批时若一人通过即可

activiti 工作流会签时为所有的都审批通过才可进入下一环节: 1.编写监听类 public class MyTaksListener implements TaskListener {     public void notify(DelegateTask ...
  • artaganan8
  • artaganan8
  • 2017-09-06 09:47
  • 3048

Activiti框架的工作流

一.Activiti的简单使用         activiti的运转是基于流程引擎ProcessEngine和数据库的,一共操作23张表,常用的有7张表,主要关于流程部署,流程定义,流程实例,任务,资源,用户和流程变量. 准备工作:导入activiti的...
  • hspringh
  • hspringh
  • 2016-12-26 13:09
  • 993
    个人资料
    • 访问:786319次
    • 积分:5612
    • 等级:
    • 排名:第5598名
    • 原创:96篇
    • 转载:1篇
    • 译文:0篇
    • 评论:299条
    博客专栏
    其他信息
    music