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

来源:互联网 发布:警察算法律工作经验 编辑:程序博客网 时间:2024/06/01 07:26

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);@Overridepublic 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);@Overridepublic 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)@SpringBootTestpublic 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;@AutowiredUserService userService;@AutowiredApplySimpleService simpleService;/** * 测试程序启动 */@Testpublic void contextLoads() {}/** * 测试数据库操作 */@Testpublic 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());}/** * 测试简单流程 */@Testpublic 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
原创粉丝点击