工作流引擎Activiti系列(一)——初识[通俗易懂]

工作流引擎Activiti系列(一)——初识[通俗易懂]1、介绍  几乎任何一个公司的软件开发都会涉及到流程,以往我们可能是这么实现的:业务表添加标志位标识流程的节点状态,关联批注表实现审核意见,根据一些业务数据分析处理逻辑,分配任务到用户,节点的调度,审批等…..这其实是很繁琐的,且不说开发起来比较混乱,维护起来更是难上加难:     Activiti刚好就能解决几乎所有的这些问题,当流程开发变得简单有趣。  官网:

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

1、介绍

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

    工作流引擎Activiti系列(一)——初识[通俗易懂]

    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>

Jetbrains全家桶1年46,售后保障稳定

    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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/215504.html原文链接:https://javaforall.net

(0)
上一篇 2025年7月14日 下午4:15
下一篇 2025年7月14日 下午4:43


相关推荐

  • SQL注入漏洞详解

    SQL注入漏洞详解目录 SQL 注入的分类判断是否存在 SQL 注入一 Boolean 盲注二 union 注入三 文件读写四 报错注入 floor 报错注入 ExtractValue 报错注入 UpdateXml 报错注入五 时间盲注六 REGEXP 正则匹配七 宽字节注入八 堆叠注入九 二次注入十 User Agent 注入十一 Cookie 注入十二 过滤绕过十三

    2026年3月26日
    2
  • wpscan使用教程

    wpscan使用教程目录概述主要参数工具使用扫描 wordpress 站点插件扫描扫描插件漏洞扫描主题扫描主题漏洞枚举 wordpress 用户名暴露激活成功教程密码结合 MSF 获取 shell 概述 WPScan 是 KaliLinux 默认自带的一款漏洞扫描工具 它采用 Ruby 编写 能够扫描 WordPress 网站中的多种安全漏洞 其中包括主题漏洞 插件漏洞和 WordPress 本身的漏洞 最新版本 WPScan 的数据库中包含超过 18000 种插件漏洞和 2600 种主题漏洞 并且支持最新版本的 WordPress 值得注意的是 它不仅能够扫描类似 robots

    2026年3月17日
    2
  • Python读txt(python打开txt文件)

    python读写txt文件准备原始txt数据3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110…

    2022年4月17日
    69
  • DCache-CacheServer分析(一)

    DCache-CacheServer分析(一)DCache 是一个基于 TARS 框架开发的分布式 NoSQL 存储系统 数据采用内存存储 支持连接后端 DB 实现数据持久化 DCache 采用集群模式 具有高扩展 高可用的特点 本文对 DCache 中 CacheServer 的结构做了总体分析 希望对初识 DCache 的开发者有所帮助

    2026年3月26日
    2
  • Pycharm调试时按F8单步调试失灵解决方法

    Pycharm调试时按F8单步调试失灵解决方法问题描述 在 pycharm 中单步调试时 有时候会遇到一种情况 按 F8 单步调试时 按键失灵 但是鼠标点击单步调试按钮时代码可以正常运行 问题出现的可能原因及解决方法 检查是否安装网易有道词典 如果安装有道词典可能是由于有道词典的取词关开快捷键占用 F8 功能导致 关闭有道词典 pycharm 的 F8 单步调试功能恢复

    2026年3月27日
    2
  • List初始化、集合复制

    List初始化、集合复制List集合复制User类classUser{privateStringa;privateStringb;}1.通过循环遍历复制List集合List<User>userList=newArrayList<>();Useruser0=newUser(“a0″,”b0”);userList.add(user0);userList.add(newUser(“

    2025年8月21日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号