乐趣区

关于后端:Activiti入门学习

原始博文链接

什么是工作流

首先还是要把专业术语给搬出来:工作流(Workflow),就是“业务过程的局部或整体在计算机应用环境下的自动化”,它次要解决的是“使在多个参与者之间依照某种预约义的规定传递文档、信息或工作的过程主动进行,从而实现某个预期的业务指标,或者促使此指标的实现”。说的艰深一点就是通过计算机利用帮忙咱们“走流程”,各种证件的办理、资格的审批在生活中无处不在,工作流就在咱们身边。

工作流这个名词概念在计算机领域中,起源于生产组织和办公自动化畛域,是针对日常工作中具备固定程序流动而提出的一个概念,目标是通过将工作分解成定义良好的工作或角色,依照肯定的规定和过程来执行这些工作并对其进行监控,达到进步工作效率、更好的管制过程、加强对客户的服务、无效治理业务流程等目标。

要走“走流程”的人是苦楚的,慢、麻烦置信是很多人对走流程的印象,而解决“走流程”的人也并不开心,简单的过程令人心力憔悴。而在这个计算机互联网时代,流程也都逐步开始“上网”,形成所谓的信息化的一个重要组成部分。这就催生了后盾工作流框架,比拟驰名的有 jBPM 和 Activiti,本文的配角就是 Activiti。

Activiti 简介

本文以 Activiti 5.22 作为示例和剖析的根底。还是先上官话:Activiti5 是由 Alfresco 软件在 2010 年 5 月 17 日公布的业务流程治理(BPM)框架,它是笼罩了业务流程治理、工作流、服务合作等畛域的一个开源的、灵便的、易扩大的可执行流程语言框架。

Activiti 实现了 BPMN 2.0 标准,能够公布设计好的流程定义,并通过 api 进行流程调度。Activiti 流程引擎重点关注在零碎开发的易用性和轻量性上。每一项 BPM 业务性能 Activiti 流程引擎都以服务的模式提供给开发人员。通过应用这些服务,开发人员可能构建出功能丰富、轻便且高效的 BPM 应用程序。

本文指标

记录上手过程,疾速了解、入门 Actitviti,并不深挖以及应用骚操作。

上手过程

筹备工作

  1. 首先 Activiti 的数据基于数据库,所以首先须要一个数据库,根本支流的数据库 Activiti 都反对,选用 mysql 就 ok。
  2. 去官网下载 Activiti,外面不仅蕴含了须要的 jar 包,还有文档、sql 文件、war 包等。
  3. 配置 IDE,尽管说 eclipse 插件是 Activiti 的一个长处,然而目前 IDEA 的风行水平更高一些,还是选用 IDEA 作为开发测试工具,IDEA 也有 Activiti 插件名为 actiBPM,然而集体感觉不太好用,截止目前这个插件最初更新工夫是 2014 年,看起来如同不在保护了,比拟难堪。
  4. 框架集成,Activiti 绝大多数状况还是作为一个组件集成到后盾框架中,为了不便,缩小其余因素烦扰,选用 SpringBoot。不过很惋惜在练习的时候想当然地选了 SpringBoot2.0,集成起来产生了问题节约了很多工夫。
  5. 简略理解下 BPMN,业务流程建模与标注(Business Process Model and Notation,BPMN),定义了流程图的内容和表白,最新的是 BPMN 2.0 标准。流程内容个别采纳 XML 格局来承载表白,通过图形化工具来疾速、直观地设计流程。

流程图图解

很多教程喜爱上来就说 API、说数据库表,但我认为还是该从最直观的流程图来作为切入点,一步一步引出各个概念。下图是一个最简略的流程图,流程的目标是员工退出公司的审批。

对应的 XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 
             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" 
             xmlns:tns="http://www.activiti.org/test" 
             xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
             expressionLanguage="http://www.w3.org/1999/XPath" 
             id="m1534942345607" name=""targetNamespace="http://www.activiti.org/test"typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="joinProcess" isClosed="false" isExecutable="true" processType="None">
    <startEvent id="_2" name="Join process">
      <extensionElements>
        <activiti:formProperty id="personId" name="person Id" required="true" type="long"/>
        <activiti:formProperty id="compId" name="company Id" required="true" type="long"/>
      </extensionElements>
    </startEvent>
    <userTask activiti:exclusive="true" id="_3" name="主管审批"
              activiti:candidateUsers="${joinService.findUsers(execution)}" isForCompensation="true">
      <extensionElements>
        <activiti:formProperty id="joinApproved" name="Join Approved" type="enum">
          <activiti:value id="true" name="Approve" />
          <activiti:value id="false" name="Reject" />
        </activiti:formProperty>
      </extensionElements>
    </userTask>
    <endEvent id="_4" name="EndEvent"/>
    <serviceTask activiti:exclusive="true" id="_5" name="审批解决" activiti:expression="${joinService.joinGroup(execution)}" />
    <sequenceFlow id="_6" sourceRef="_2" targetRef="_3"/>
    <sequenceFlow id="_7" sourceRef="_3" targetRef="_5"/>
    <sequenceFlow id="_8" sourceRef="_5" targetRef="_4"/>
  </process>
  <bpmndi:BPMNDiagram documentation="background=#FFFFFF;count=1;horizontalcount=1;orientation=0;
  width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0"id="Diagram-_1"name="New Diagram">
    <bpmndi:BPMNPlane bpmnElement="myProcess_1">
      <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
        <omgdc:Bounds height="32.0" width="32.0" x="70.0" y="181.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
        <omgdc:Bounds height="55.0" width="85.0" x="160.0" y="170.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
        <omgdc:Bounds height="32.0" width="32.0" x="455.0" y="181.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
        <omgdc:Bounds height="55.0" width="85.0" x="310.0" y="170.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_6" id="BPMNEdge__6" sourceElement="_2" targetElement="_3">
        <omgdi:waypoint x="102.0" y="197.5"/>
        <omgdi:waypoint x="160.0" y="197.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7" sourceElement="_3" targetElement="_5">
        <omgdi:waypoint x="245.0" y="197.5"/>
        <omgdi:waypoint x="310.0" y="197.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_5" targetElement="_4">
        <omgdi:waypoint x="395.0" y="197.5"/>
        <omgdi:waypoint x="455.0" y="197.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

图中内容相当简略,两个开始和完结的圆圈,两个流程的步骤。

先用直白的文字描述这个流程:人事提交员工退出公司的审批 -> 主管审批 -> 完结,通过后要生成一条入职数据。

而流程图中体现的是:开始流程 -> 主管审批 -> 审批解决 -> 完结。

可见还是有肯定的差异,依据我集体的感觉,BPMN 流程图的表白和直白的思维是有肯定的区别的,这也是我一开始上手时感到困惑的点。其一是 Activiti 流程开始后并不会在开始节点停留,所以提交审批这个流程在图中没有间接的体现,其二是对于一个审批工作来说艰深思维会认为审批和解决属于同一步操作,而对于 Activiti 每一步操作是一个工作,工作辨别明确,其中尤以人为的操作(UserTask)和程序处理(ServiceTask)这两个为主,因而主管审批是一步,而审批解决生成数据是另外一步。

图中 bpmndi:BPMNDiagram 节点下的内容代表的是流程图各个节点的地位信息,以图的左上角为原点,用 xy 坐标值示意流程节点在图中的地位。

次要概念

工作

很天然地引申出工作这个点,更精确地说应该是执行打算(excution)。Task 用来形容业务过程中所有可能产生工时的行为,它次要包含 UserTask、ServiceTask、ScriptTask、ReceiveTask、MailTask 等等。具体阐明一下其中最根底的两种:

  1. UserTask:人工工作,用来形容认为参加的操作,流程执行到此节点时须人工响应后能力持续向下流转。人工工作最终要的属性就是办理工作的执行者,有 assignee(繁多执行人)、candidateUsers(多个候选执行人)、candidateGroups(候选执行组)这几种属性可选。
  2. ServiceTask:Java 服务工作,容许指定一个实现了指定接口的 java 类,或者执行一个表达式。与 User Task 不同,流程引擎流经此节点会主动调用 Java 类中定义的办法,办法执行结束主动向下一流程节点流转。

程序流

有了工作节点就天然须要把他们连接起来,图中的箭头连线称为程序流(sequenceFlow),用于形容节点的流转方向和程序。次要属性有 sourceRef(起始节点 Id)、targetRef(指向节点 Id)、conditionExpression(条件限度的表白)。

网关

网关(gateways)在示例的图中没有体现,然而它是流程定义重要的因素之一。实在的流程并不会如此简略,很多时候流程须要分叉、并行等等,而网关就是用来决定流程流转指向的,可能会被用作条件分支或聚合,也能够被用作并行执行或基于事件的排它性条件判断。罕用的网关有互斥关口(exclusiveGateway,流程通过时只能走其中一个程序流)和并行关口(parallelGateway,通过关口后会同时通过所有程序流,所有流程实现后会一起通过指向的并行关口)。

事件

说完上述的还有两个圆圈没有讲到,在 BPMN 标准下圆圈个别示意事件。启动、完结、边界条件以及每个流动的创立、开始、流转等都是流程事件,利用事件机制,能够通过事件控制器为零碎减少辅助性能。开始和完结是每个流程都必须蕴含的事件节点。

工作和程序流以及未介绍的子流程能够同称为流动(Activities),加上网关和事件就形成了 BPMN2.0 对流程执行语义定义的三类基本要素。

流程变量

流程变量在整个工作流中用于传递业务变量,流程变量的作用域范畴是只对应一个流程实例,在开启流程和实现工作时都能够设置变量,间接设置变量时,分 setVariable 和 setVariableLocal,local 示意绑定当前任务,流程继续执行时下个工作获取不到这个流程变量,波及的数据库表为 act_ru_variable、act_hi_varinst(变量历史记录)。

留神,流程变量须要实现 Serializable 接口且要求过程中属性不能变动(反序列化),须要增加序列化 ID,如果是 JavaBean 作为流程变量,序列化的 bean 会寄存到 act_ge_bytearray 这张表中。

流程能够定义须要哪些变量,能够查看 xml 中 activiti:formProperty 相干的信息。

外围 API

理解了流程图之后,介绍 Activiti 的外围 API,疾速造成对于 Activiti 的基本概念。Activiti 最外围的类是流程引擎(ProcessEngine),其余所有类都通过引擎来获取。引擎能够获取各种各种各样的服务(Service)对应解决各种需要,所有流程的具体操作都对应执行某一项服务提供的办法。

服务

  1. RepositoryService:仓库服务。业务流程的定义都须要应用一些定义文件,定义了流程须要将其部署,部署之后可能须要查问部署的信息和相干的文件,这些需要就由 RepositoryService 提供。
  2. RuntimeService:流程执行服务。在 Activiti 中,每当一个流程定义被启动一次之后,都会生成一个相应的流程对象实例。RuntimeService 提供了启动流程、查问流程实例、设置获取流程实例变量等性能。
  3. TaskService:工作服务。它提供了运行时工作查问、支付、实现、删除以及变量设置等性能。
  4. HistoryService:历史服务。流程、工作执行实现之后可能须要追溯、查问历史,这就须要用到 HistoryService。
  5. IdentityService:身份服务。Activiti 中内置了用户以及组治理的性能,必须应用这些用户和组的信息能力获取到相应的 Task。IdentityService 提供了对 Activiti 零碎中的用户和组的治理性能。当然用户和组也能够自定义提供,然而这些内容不在本文探讨范畴之内
  6. ManagementService: 治理服务。它提供了对 Activiti 流程引擎的治理和保护性能,这些性能不在工作流驱动的应用程序中应用,次要用于 Activiti 零碎的日常保护。

对象

除了服务,还有以接口模式表白的几个要害对象:

  1. Deployment:流程部署对象,是对一个部署的抽象化表白。
  2. ProcessDefinition:流程定义,部署胜利后主动创立。
  3. ProcessInstance:代表流程实例,启动流程时创立。
  4. Execution:执行打算,流程实例和流程执行中的所有节点都是 Execution。当流程复线执行时 ProcessInstance 与 Execution 内容保持一致,并发流程中,总线路为 ProcessInstance,分线路中每个流动由 Execution 表白。
  5. Task:工作,在 Activiti 中的 Task 仅指有角色参加的工作,包含上述的 UserTask 以及 MannualTask。

入门示例

说完了概念性的货色,接下来就须要残缺地走一遍流程。示例的同时介绍相干的数据表,Activiti 所有的内容信息都以数据库作为根底,各种服务提供的查问实质上都是对数据库的查问。

还是以上述的简略流程作为示例来进行演示。

工程搭建

关上 IDEA 创立一个 SpringBoot 我的项目(能够选 2.0,有坑然而会加以阐明解决),勾选组件:Web、JPA(想用其余的 ORM 也能够)、MySQL 即可,我的项目构建采纳 Maven。工程创立胜利后,在 POM 文件中减少 Activiti 的依赖。

<dependency>
   <groupId>org.activiti</groupId>
   <artifactId>activiti-spring-boot-starter-basic</artifactId>
   <version>5.22.0</version>
</dependency>

这里有个整合的坑点,Activiti 目前的版本落后于 SpringBoot 和 SpringSecurity,如果间接就这么运行工程会产生短少 SpringSecurity 依赖的谬误,然而能够在 POM 中能够看到 SpringSecurity 的依赖的 Optional 属性为 True,而且平安相干的主动配置增加了@AutoConfigureBefore,确保在 SpringSecurity 主动配置实现后执行。尝试退出 SpringSecurity 的依赖仍然报错,能够发现 Activiti 里依赖的一个类在 SpringSecurity5.0 版本之后曾经挪动了地位。因而必须强制排除产生谬误的 Activiti 的主动配置类,批改主类 Application 如下:

@EnableAutoConfiguration(exclude = {org.activiti.spring.boot.SecurityAutoConfiguration.class})
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);
  }
}

数据筹备与流程部署

创立 Person 和 Comp 两个实体类以及相干的 JpaRepository,用于示意员工和公司以及体现生成数据的操作。而后保留几个实例以供应用。

@Entity
public class Person {
   @Id
   @GeneratedValue
   private Long personId;
    
   private String personName;
    
   @ManyToOne
   private Comp comp;
    
   public Person(String personName) {this.personName = personName;}
    
    // Getter & Setter
    // ...
}

@Entity
public class Comp {

    @Id
    @GeneratedValue
    private Long compId;

    private String compName;

    @OneToMany(mappedBy = "comp")
    private List<Person> people;

    public Comp(String compName) {this.compName = compName;}
    
    // Getter & Setter
    // ...
}

在测试类中写入:

@Autowired
private PersonRepository personRepository;
@Autowired
private CompRepository compRepository;
@Before
public void contextLoads() {
  // 筹备数据
  if (personRepository.findAll().size() == 0) {personRepository.save(new Person("wtr"));
      personRepository.save(new Person("wyf"));
      personRepository.save(new Person("admin"));
  }
  if (compRepository.findAll().size() == 0) {Comp group = new Comp("great company");
      compRepository.save(group);
      Person admin = personRepository.findByPersonName("admin");
      Person wtr = personRepository.findByPersonName("wtr");
      admin.setComp(group); wtr.setComp(group);
      personRepository.save(admin); personRepository.save(wtr);
  }
}

接下来将下面的流程 XML 代码拷贝进入一个 xml 文件,在 resource 目录下新建一个 process 文件夹,将 xml 文件放入这个文件夹,复制文件更改后缀为 bpmn,这么做是因为 IDEA 的插件编辑器无奈编辑某些属性,而且从新关上 bpmn 文件会发现配置的属性看不到,所以会把 xml 放在同一个目录下进行参考。设计流程时能够先用插件画图,而后更改为 xml 后缀进行属性编辑,编辑实现后复制一份并更改为 bpmn 后缀。

因为和 springboot 集成,process 目录下的流程会主动部署,省去了部署这件事,不过还是把一般的部署代码贴出来。

@Test
public void showDeploy(){ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
   Deployment deploy = processEngine.getRepositoryService()
                    .createDeployment()
                    .name("testDeploy")
                    .addClasspathResource("processes/example.bpmn")
                    .deploy();
   System.out.println(deploy.getId() + " " + deploy.getName());
}

与部署相干的数据表以 ACT_RE 结尾,在执行以上步骤或者主动部署后,能够在相干表中查看到新生成的部署信息以及流程定义的信息。另外流程文件(包含 bpmn、png、bpmn20.xml 等)会间接以二进制模式存入 act_ge_bytearray 表,ACT_GE 结尾的表寄存通用数据。

同时,还须要筹备身份信息,也就是增加执行人以及执行组,然而这一步并不是必要的,起因同样能够从数据库中窥得一二。上文提到了 Activiti 提供了一个默认的身份服务,相干的数据表以 ACT_ID 结尾,很显著 act_id_user 寄存的就是用户的信息,不过工作相干的表并没有和用户表有外键束缚,所以工作执行的时候即便用户表中没有相干信息,相干的工作表仍然能够存储用户的 ID 标识,也能够以 ID 来查问。同样还是放出一段增加用户和组的代码,以供理解参考,示例工程为了不便就不增加用户和组了。

@Test
public void addUserAndGroup(){ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
   IdentityService identityService = processEngine.getIdentityService();
   identityService.saveGroup(new GroupEntity("主管"));// 建设组
   identityService.saveGroup(new GroupEntity("经理"));
   identityService.saveUser(new UserEntity("小明"));// 建设用户
   identityService.saveUser(new UserEntity("小红"));
   UserEntity littileMount = new UserEntity("小山");
   littileMount.setEmail("xxx@fake.com"); // 设置用户相干详细信息
   identityService.saveUser(littileMount);
   identityService.createMembership("小明", "主管");// 建设组和用户关系
   identityService.createMembership("小红", "主管");
   identityService.createMembership("小山", "经理");
}

开启流程实例

以下相干操作为了不便都写在测试方法中,更规范地做法是写几个 Controller 和 Service 来进行申请,不过理论失效的代码是统一的。不要立马运行这些代码,因为前面还须要写一些货色,看完一遍当前再入手练习。

筹备得当之后,首先就是开启一个流程。每开启一个定义好的流程就会产生一个流程实例,相干的数据表为 act_ru_execution。

@Autowired
private RuntimeService runtimeService;

@Test
public void startProcess() {runtimeService.startProcessInstanceByKey("joinProcess");
}

因为和 Spring 整合,Activiti 的引擎和服务都在 Spring 中以供拆卸。开启流程只有一句话,很简略,给出的这个参数值能够在定义流程的 xml 中找到,找到了天然就了解了。不过认真想想,其实还漏了一些货色,开始流程的时候须要提供这个审批过程须要的信息,就好比去办手续总是要你提交身份证复印件一样。对于这个审批员工退出公司的示例流程来说,最根本的信息就是两个:员工 id 和公司 id,须要在流程开启时传入,这就是流程变量的概念。所以残缺的开启流程代码应该如下所示:

@Autowired
private RuntimeService runtimeService;

@Test
public void startProcess() {Person wyf = personRepository.findByPersonName("wyf");
   Comp comp = compRepository.findAll().get(0);
   Map<String, Object> variables = new HashMap<String, Object>();
   variables.put("personId", wyf.getId()); // 员工 id
   variables.put("compId", comp.getId()); // 公司 id
   runtimeService.startProcessInstanceByKey("joinProcess",variables);
}

实现人工工作

如之前所说,流程开启后不会在开始节点停留,那么很显然目前流程位于主管审批这个节点。人工工作须要响应后流程才会持续,这一步就是抽象化的主管审批动作。

查问工作

首先,Activiti 须要晓得由谁来执行某个工作,查看流程 xml 文件能够发现 userTask 节点有一个属性:activiti:candidateUsers,这就是在指定执行工作的候选人。它的值是一个表达式(也能够间接填入候选人的 id,指定执行者有多种办法),能够了解为执行某个 java 办法来获取候选人的 id。创立一个类 JoinService,并且将其交由 Spring 治理。

@Service
public class JoinService {
  // 获取符合条件的审批人,演示不便这里写死,应用时利用理论代码
  public List<String> findUsers(DelegateExecution execution) {return Arrays.asList("admin", "wtr");
  }
}

这就对应了表达式:"${joinService.findUsers(execution)}"。这里指定了 admin 和 wtr 能够执行这个审批。然而理论利用过程中工作不会间接摆在审批人背后,咱们须要查问工作。查问工作的形式有许多种,这里就介绍最根本的依照用户 id 查问。

@Autowired
private ActivitiService activitiService;
@Test
public void query() {List<Task> tasks = activitiService.getTasks("admin");
  System.out.println("----------------- task size :"+tasks.size());
  for (Task task : tasks){System.out.println("Id :"+task.getId()+"Name :"+task.getName());
  }
  return ;
}
执行实现

查问到这个工作后就能够将其实现。代码也很少,不过别忘了输出代表审批后果的参数。执行完这个办法后,人工工作就实现了,流程将进入下一个节点。

@Autowired
private TaskService taskService;
@Test
public void completeTasks() {Map<String, Object> taskVariables = new HashMap<String, Object>();
  taskVariables.put("joinApproved", true); // 这里间接给予 true 示意通过
  String taskId = "1"; // 更改成上个办法查问出的工作 Id
  taskService.complete(taskId, taskVariables); 
}

服务工作的执行

能够在图中看到接下来的节点是一个服务工作。如上文所述,与人工工作不同,服务工作会在执行完设置的办法或者表达式之后主动完结进入下一步。那么很显然最重要的就是如何设置执行的办法,查看流程定义 xml 文件中的 serviceTask 节点,很显著就是它的 activiti:expression 属性指定了执行的办法。依据这个属性值,须要在之前创立的 JoinService 类中增加一个名为 joinGroup 的办法,残缺的 JoinService 类如下。

@Service
public class JoinService {
   @Autowired
   PersonRepository personRepository;
   @Autowired
   private CompRepository compRepository;
   
   // 退出公司操作,可从 DelegateExecution 获取流程中的变量
   public void joinGroup(DelegateExecution execution) {Boolean bool = execution.getVariable("joinApproved",Boolean.class);
       if (bool) {Long personId = execution.getVariable("personId", Long.class);
          Long compId = execution.getVariable("compId",Long.class);
          Comp comp = compRepository.findById(compId).get();
          Person person = personRepository.findById(personId).get();
          person.setComp(comp);
          personRepository.save(person);
          System.out.println("退出组织胜利");
       } else {System.out.println("退出组织失败");
       }
    }
    
    // 获取符合条件的审批人,演示不便这里写死,应用时利用理论代码
    public List<String> findUsers(DelegateExecution execution) {return Arrays.asList("admin", "wtr");
    }
}

在 joinGroup 办法中能够通过入参 DelegateExcution 来获取流程中的参数。如果审批通过则在数据库中减少 Person 和 Comp 的关联,示意员工退出了公司。

查问历史记录

到上一步其实能够发现整个示例流程曾经完结。然而还有一个很重要的需要就是历史记录的查问,流程实例完结之后能够查问相干的历史记录,次要包含历史流程实例查问、历史流动实例查问、历史工作实例查问和历史流程变量查问等,这些办法都来自 HistoryService。历史相干的数据库表以 ACT_HI 结尾,一共有 8 张历史记录相干的表。

值得一提的是正在运行中的流程相干信息由 RuntimeService 提供查问,而完结的流程信息才可能通过 HistoryService 获取到,信息存储在不同的数据表,这是为了缩小单表数据量提高效率,大部分的操作次要是对执行中流程的查问。因而在人工工作期待期间能够在 act_ru_execution 表中查到相干数据,而流程完结之后能够发现相干信息曾经从表中删除。

总结

看完上述内容,并且实际过示例流程后,置信曾经建设了对于 Activiti 的根本了解,对于创立、解决简略的流程应该不成问题,当然理论我的项目的利用须要解决的问题肯定不限于此,Activiti 框架自身也不止于此。本文只是入门,想进一步理解还是应该查看官网文档、源码以及高阶的教程。

另外,官网下载的 Activiti 文件中蕴含了一个演示我的项目的 war 包:activiti-explorer.war,部署后能够在线编辑流程图,作为一个官网 Demo 也有助于疾速入门。部署也比较简单,在 mysql 中创立一个数据库,应用给予的 sql 文件创建 Activiti 相干的表,而后将 war 包解压置入 tomcat,找到 activiti-explorer\WEB-INF\classes 下的 db.properties 配置文件并关上,批改数据库连贯信息如下。

db=mysql
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/activiti #更改为创立的数据库名
jdbc.username=root #数据库用户
jdbc.password=123456 #用户明码

复制 mysql 连贯的 jar 包 mysql-connector-java-xxx.jar(没有的话先下载)到 WEB-INF\lib 目录下即可。启动 tomcat,不出问题关上 http://localhost:8080/activiti-explorer,应用用户 kermit,明码 kermit 登录即可开始体验操作。

退出移动版