工作流 七月 07, 2020

activit工作流(一) 概念

文章字数 21k 阅读约需 19 mins. 阅读次数 0

activit工作流(一) 概念

activiti介绍

引擎service接口

  1. RespositoryService: 流程仓库Service,用于管理流程仓库.eg:部署,删除,读取流程资源
  2. identifyService: 身份Service, 可以管理和查询用户,组之间的关系.(版本7之后删除)
  3. RuntimeService: 运行时Service,可以处理所有正在运行状态的流程实例,任务等.
  4. TaskService: 任务Service,用于管理,查询任务, eg:签收,办理,指派等.
  5. FormService: 表单Service,用于读取和流程任务相关的表单数据(版本7之后删除)
  6. HistoryService: 历史Service, 可以查询所有历史数据, 例如:流程实例,任务,活动,变量,附件等
  7. ManagementService: 引擎管理Service, 和具体业务无关,主要是可以查询引擎配置,数据库,作业等

流程设计器

  • Eclipse Designer
  • Activiti Modeler

架构与组件

  • activiti Engine(最核心模块): 解析,执行,创建,管理(任务流程实例), 查询历史记录.
  • activiti modeler: 模型设计器
  • activiti designer: 流程设计器
  • activiti explorer: 用来管理仓库,用户,组,启动流程, 任务管理等,提供rest风格的api
  • activiti rest: 提供restful风格的服务,允许客户端以json的方式,语音穷拐的rest api交互,以此跨平台,跨语言

运行第一个activiti程序(springboot)

流程绘制

生成springboot项目

生成空的springboot项目

pom文件添加依赖

<-- activiti 引擎依赖-->
<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring-boot-starter-basic</artifactId>
    <version>6.0.0</version>
</dependency>
<-- mysql 数据源依赖 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

配置文件添加数据源与activiti配置.

server:
  port: 8090
spring:
  activiti:
#    database-schema-update: true
    check-process-definitions: false
    historyLevel: audit
    db-history-used: true
  application:
    name: konghenying-activiti
  datasource:
    username: konghenying
    password: 123456
    url: jdbc:mysql://localhost:3306/activiti?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false
    driver-class-name: com.mysql.jdbc.Driver

配置项说明:

  • database-schema-update 是否更新数据库

    • false: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。(生产环境常用)
    • activiti: 会对数据库中所有表进行更新操作。如果表不存在,则自动创建。(开发时常用)
    • create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。(单元测试常用)
    • drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)。
  • historyLevel 历史数据等级

    • none: 不保存任何的历史数据,因此,在流程执行过程中,这是最高效的
    • activity: 级别高于none,保存流程实例与流程行为,其他数据不保存
    • audit: 除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值
    • full: 保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等
  • db-history-used 检测历史表是否存在(activiti6默认启用,activiti7默认关闭)

  • check-process-definitions 启动的时候是否自动部署流程

实装流程图

将生成的bpmn文件放入/resources/processes文件夹下.通过代码或者自动部署流程.

常用功能案例:以请假为例

第一步: 流程部署

@Resource
private RepositoryService repositoryService;
@Test
public void deploy(){
    String bpmnNameAndKey = "first";
    Deployment deploy = repositoryService.createDeployment()
        .addClasspathResource("processes/first.bpmn")
//        .addClasspathResource("processes/first.png")
        .key(bpmnNameAndKey)
        .category("HR")
        .deploy();
    System.out.println("流程部署ID\t" + deploy.getId());
    System.out.println("流程keyID\t" + deploy.getKey());
    System.out.println("流程名称ID\t" + deploy.getName());
    System.out.println("流程分类ID\t" + deploy.getCategory());
}

第二步: 启动流程实例

本例中相当于提交一次请假申请

@Resource
private RuntimeService runtimeService;
@Test
public void start(){
    String bpmnNameAndKey = "first";
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(bpmnNameAndKey);
    System.out.println("流程实例ID\t" + processInstance.getId());
    System.out.println("流程定义ID\t" + processInstance.getProcessDefinitionId());
    System.out.println("流程定义key\t" + processInstance.getProcessDefinitionKey());
}

第三步: 查找个人代办任务列表

@Resource
private TaskService taskService;
@Test
public void findMyTask(){
    String assignee = "张三";
    List<Task> taskList = taskService.createTaskQuery().taskAssignee(assignee).list();
    if (!taskList.isEmpty()) {
        for (Task task : taskList) {
            System.out.println("任务ID\t" + task.getId());
            System.out.println("任务名称\t" + task.getName());
            System.out.println("任务执行人\t" + task.getAssignee());
        }
    }
}

第四步: 执行代办任务

@Resource
private TaskService taskService;
@Test
public void complet(){
    String taskId = "2505";
    taskService.complete(taskId);
    System.out.println("任务执行完成");
}

第五步: 查看历史流程实例

@Resource
private HistoryService historyService;
@Test
public void history(){
    String bpmnNameAndKey = "first";
    List<HistoricProcessInstance> historicProcessInstances=    historyService.createHistoricProcessInstanceQuery().processDefinitionKey(bpmnNameAndKey).list();
    if (!historicProcessInstances.isEmpty()) {
        for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
            System.out.println("业务系统key\t" + historicProcessInstance.getBusinessKey());
            System.out.println("部署对象ID\t" + historicProcessInstance.getDeploymentId());
            System.out.println("执行时长\t" + historicProcessInstance.getDurationInMillis());
            System.out.println("流程定义ID\t" + historicProcessInstance.getProcessDefinitionId());
            System.out.println("流程定义的key\t" + historicProcessInstance.getProcessDefinitionKey());
            System.out.println("流程定义名称\t" + historicProcessInstance.getProcessDefinitionName());
        }
    }
}

第六步: 查看历史任务

@Resource
private HistoryService historyService;
@Test
public void historyTask(){
    List<HistoricTaskInstance> historicTaskInstanceList =  historyService.createHistoricTaskInstanceQuery().list();
    if (!historicTaskInstanceList.isEmpty()){
        for (HistoricTaskInstance historicTaskInstance : historicTaskInstanceList) {
            System.out.println("任务执行人\t" + historicTaskInstance.getAssignee());
            System.out.println("任务名称\t" + historicTaskInstance.getName());
            System.out.println("任务ID\t" + historicTaskInstance.getId());
            System.out.println("流程实例ID\t" + historicTaskInstance.getProcessInstanceId());
            System.out.println("*****************");
        }
    }
}

查询功能案例:以用户为例

插入测试数据

@Resource
private IdentityService identityService;
@Test
public void insert() {
    for (int i = 0; i < 10; i++) {
        User user = identityService.newUser(String.valueOf(i));
        user.setLastName("张三" + i);
        user.setFirstName("法外狂徒" + i);
        user.setEmail("邮件" + i);
        identityService.saveUser(user);
    }
}

查询指定用户名的用户数据

@Resource
private IdentityService identityService;
@Test
public void querySingle() {
    User user = identityService.createUserQuery().userFirstName("法外狂徒1").singleResult();
    System.out.println(user.getFirstName()+"   :   " + user.getEmail());
}

查询用户列表数据

@Resource
private IdentityService identityService;
@Test
public void queryList() {
    List<User> list = identityService.createUserQuery()
            .list();
    if (!list.isEmpty()) {
        for (User user : list) {
            System.out.println(user.getFirstName() + "\t" + user.getEmail());
        }
    }
}

查询用户列表的分页数据

@Resource
private IdentityService identityService;
@Test
public void pageList(){
    // .listPage(firstResult,maxResults)
    List<User> users = identityService.createUserQuery().listPage(5,5);
    if (!users.isEmpty()){
        for (User user : users) {
            System.out.println(user.getFirstName()+"   :   " + user.getEmail());
        }
    }
}

查询用户数量

@Resource
private IdentityService identityService;
@Test
public void userListCount(){
    Long count = identityService.createUserQuery().count();
    System.out.println(count);
}

单个字段排序

@Resource
private IdentityService identityService;
@Test
public void querySingleSort() {
    List<User> list = identityService.createUserQuery().orderByUserId().asc().list();
    if (list.isEmpty()) {
        for (User user : list) {
            System.out.println(user.getFirstName() + "\t" + user.getEmail());
        }
    }
}

多个字段排序

注意:一个排序字段后需要加升降序条件.不可省略.否则会被后面的排序条件覆盖.

@Resource
private IdentityService identityService;
@Test
public void queryMultiSort() {
    UserQuery userQuery = identityService.createUserQuery().orderByUserId().desc().orderByUserEmail().asc();
    List<User> list = userQuery.list();
    if (!CollectionUtils.isEmpty(list)) {
        for (User user : list) {
            System.out.println(user.getFirstName() + "\t" + user.getEmail());
        }
    }
}

根据条件查询

@Resource
private IdentityService identityService;
@Test
public void queryCondition() {
    String firstName = "法外狂徒5";
    String firstNameLike = "法外狂徒";
    //        List<User> list = identityService.createUserQuery().userFirstName(firstName).list();
    List<User> list = identityService.createUserQuery().userFirstNameLike("%"+firstNameLike+"%").list();
    if (!CollectionUtils.isEmpty(list)) {
        for (User user : list) {
            System.out.println(user.getFirstName() + "\t" + user.getEmail());
        }
    }
}

自定义查询

@Resource
private IdentityService identityService;
@Test
public void queryNative() {
    String sql = "select  * from ACT_ID_USER";
    List<User> list = identityService.createNativeUserQuery().sql(sql).list();
    if (!CollectionUtils.isEmpty(list)) {
        for (User user : list) {
            System.out.println(user.getFirstName() + "\t" + user.getEmail());
        }
    }
}

底层为mybatis查询,mapper文件在org.activiti.db.mapping.entity.User.xml

<?xml version="1.0" encoding="UTF-8" ?> 

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 
  
<mapper namespace="org.activiti.engine.impl.persistence.entity.UserEntityImpl">

  <!-- USER INSERT -->

  <insert id="insertUser" parameterType="org.activiti.engine.impl.persistence.entity.UserEntityImpl">
    insert into ${prefix}ACT_ID_USER (ID_, REV_, FIRST_, LAST_, EMAIL_, PWD_)
    values (
      #{id ,jdbcType=VARCHAR},
      1,
      #{firstName ,jdbcType=VARCHAR},
      #{lastName ,jdbcType=VARCHAR},
      #{email ,jdbcType=VARCHAR},
      #{password ,jdbcType=VARCHAR}
    )
  </insert>

  <insert id="bulkInsertUser" parameterType="java.util.List">
    INSERT INTO ${prefix}ACT_ID_USER (ID_, REV_, FIRST_, LAST_, EMAIL_, PWD_) VALUES 
      <foreach collection="list" item="user" index="index" separator=",">
        (#{user.id ,jdbcType=VARCHAR},
         1,
         #{user.firstName ,jdbcType=VARCHAR},
         #{user.lastName ,jdbcType=VARCHAR},
         #{user.email ,jdbcType=VARCHAR},
         #{user.password ,jdbcType=VARCHAR})
      </foreach>
  </insert>

  <insert id="bulkInsertUser" databaseId="oracle" parameterType="java.util.List">
    INSERT ALL 
      <foreach collection="list" item="user" index="index">
        INTO ${prefix}ACT_ID_USER (ID_, REV_, FIRST_, LAST_, EMAIL_, PWD_) VALUES 
        (#{user.id ,jdbcType=VARCHAR},
         1,
         #{user.firstName ,jdbcType=VARCHAR},
         #{user.lastName ,jdbcType=VARCHAR},
         #{user.email ,jdbcType=VARCHAR},
         #{user.password ,jdbcType=VARCHAR})
      </foreach>
    SELECT * FROM dual
  </insert>

  <!-- USER UPDATE -->

  <update id="updateUser" parameterType="org.activiti.engine.impl.persistence.entity.UserEntityImpl">
    update ${prefix}ACT_ID_USER set
      REV_ = #{revisionNext ,jdbcType=INTEGER},
      FIRST_ = #{firstName ,jdbcType=VARCHAR},
      LAST_ = #{lastName ,jdbcType=VARCHAR},
      EMAIL_ = #{email ,jdbcType=VARCHAR},
      PWD_ = #{password ,jdbcType=VARCHAR},
      PICTURE_ID_ = #{pictureByteArrayRef ,typeHandler=ByteArrayRefTypeHandler}
    where ID_ = #{id}
      and REV_ = #{revision}
  </update>
  
  <!-- USER DELETE -->

  <delete id="deleteUser" parameterType="org.activiti.engine.impl.persistence.entity.UserEntityImpl">
    delete from ${prefix}ACT_ID_USER where ID_ = #{id} and REV_ = #{revision}
  </delete>

  <!-- USER RESULTMAP -->

  <resultMap id="userResultMap" type="org.activiti.engine.impl.persistence.entity.UserEntityImpl">
    <id property="id" column="ID_" jdbcType="VARCHAR" />
    <result property="revision" column="REV_" jdbcType="INTEGER" />
    <result property="firstName" column="FIRST_" jdbcType="VARCHAR" />
    <result property="lastName" column="LAST_" jdbcType="VARCHAR" />
    <result property="email" column="EMAIL_" jdbcType="VARCHAR" />
    <result property="password" column="PWD_" jdbcType="VARCHAR" />
    <result property="pictureByteArrayRef" column="PICTURE_ID_" typeHandler="ByteArrayRefTypeHandler" />
  </resultMap>
  
  <!-- USER SELECT -->

  <select id="selectUser" parameterType="string" resultMap="userResultMap">
    select * from ${prefix}ACT_ID_USER where ID_ = #{id,jdbcType=VARCHAR}
  </select>
    
  <select id="selectUserByQueryCriteria" parameterType="org.activiti.engine.impl.UserQueryImpl" resultMap="userResultMap">
   ${limitBefore}
    select RES.* ${limitBetween}
    <include refid="selectUserByQueryCriteriaSql" />
    ${orderBy}
    ${limitAfter}
  </select>
  
   <select id="selectUserCountByQueryCriteria" parameterType="org.activiti.engine.impl.UserQueryImpl" resultType="long">
    select count(RES.ID_)
    <include refid="selectUserByQueryCriteriaSql" />
  </select>
  
  <sql id="selectUserByQueryCriteriaSql">
    from ${prefix}ACT_ID_USER RES 
    <if test="groupId != null">
      inner join ${prefix}ACT_ID_MEMBERSHIP M on RES.ID_ = M.USER_ID_
      inner join ${prefix}ACT_ID_GROUP G on M.GROUP_ID_ = G.ID_
    </if>
    <where>
      <if test="id != null">
        RES.ID_ = #{id}
      </if>
      <if test="firstName != null">
        and RES.FIRST_ = #{firstName}
      </if>
      <if test="firstNameLike != null">
        and RES.FIRST_ like #{firstNameLike}${wildcardEscapeClause}
      </if>
      <if test="lastName != null">
        and RES.LAST_ = #{lastName}
      </if>
      <if test="lastNameLike != null">
        and RES.LAST_ like #{lastNameLike}${wildcardEscapeClause}
      </if>
      <if test="fullNameLike != null">
        and (RES.FIRST_ like #{fullNameLike}${wildcardEscapeClause} or RES.LAST_ like #{fullNameLike}${wildcardEscapeClause})
      </if>
      <if test="email != null">
        and RES.EMAIL_ = #{email}
      </if>
      <if test="emailLike != null">
        and RES.EMAIL_ like #{emailLike}${wildcardEscapeClause}
      </if>
      <if test="groupId != null">
        and G.ID_ = #{groupId}
      </if>
      <if test="procDefId != null">
        and exists (select ID_ from ${prefix}ACT_RU_IDENTITYLINK where PROC_DEF_ID_ = #{procDefId} and USER_ID_=RES.ID_ )
      </if>
      
    </where>
  </sql>

  <select id="selectUserByNativeQuery" parameterType="java.util.Map" resultMap="userResultMap">
    <include refid="org.activiti.engine.db.common.selectByNativeQuery"/>
  </select>

  <select id="selectUserCountByNativeQuery" parameterType="java.util.Map" resultType="long">
    ${sql}
  </select>
  
</mapper>

表结构

表结构

0%