大家好,又见面了,我是你们的朋友全栈君。
1、介绍
几乎任何一个公司的软件开发都会涉及到流程,以往我们可能是这么实现的:业务表添加标志位标识流程的节点状态,关联批注表实现审核意见,根据一些业务数据分析处理逻辑,分配任务到用户,节点的调度,审批等…..这其实是很繁琐的,且不说开发起来比较混乱,维护起来更是难上加难:
Activiti刚好就能解决几乎所有的这些问题,当流程开发变得简单有趣。
官网:https://www.activiti.org/
官方文档:https://www.activiti.org/userguide/
Activiti项目是一项新的基于Apache许可的开源BPM平台,从基础开始构建,旨在提供支持新的BPMN 2.0标准,包括支持对象管理组(OMG),面对新技术的机遇,诸如互操作性和云架构,提供技术实现。
作为开发者,使用Activiti带给我的直接好处:
- 天然支持Spring(Spring需要在配置文件中自己定义Activiti的Bean,Spring Boot则不需要)
- 流程定义通过画流程图实现(官方提供了相关工具,Eclipse也有插件支持),简单直观,易维护,易修改。
- 审批条件参数化,流程分支简单实现。
- 审批人可使用多种方式设置(支持用户、用户组、角色、候选组以及监听器动态设置),灵活,简单。
- 统一的审批接口,并不需要判断流程当前节点和走向。
- 提供强大的JPA查询,同时支持Name Query和Native Query。
- 流程数据与业务数据分离。
后续文章会一步步介绍Activiti的功能,主要使用基于Spring Boot的工程,也会提供单纯的Spring工程Demo。
2、示例
此处演示一个小示例,暂不解释代码,仅仅看看是怎样用activiti实现的。
场景就是请假,不过这里稍稍多了点内容,就是请假由请假人对应部门的领导审批,而不是统一的某一部分人。
2.1、使用Spring Boot工程
首先创建Spring boot工程,为了演示方便,使用内存数据库,完整pom文件如下:
代码语言:javascript复制<?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文件:
代码语言:javascript复制<?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、监听器
监听器分任务监听器和流程监听器。
任务监听器
代码语言:javascript复制/**
* 领导审核监听器
* @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);
}
}
流程监听器(此处并无实际代码,只给写法):
代码语言:javascript复制/**
* 流程监听器
* @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 修改业务数据状态
}
}
单元测试
代码语言:javascript复制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
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/215504.html原文链接:https://javaforall.cn