zoukankan      html  css  js  c++  java
  • Activiti6详细教程

    一、为什么选择Activiti

    activiti介绍 Activiti是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理,工作流,服务协作等领域的一个开源,灵活的,易扩展的可执行流程语言框架。

     解决方案优点缺点选型结果选型原因
    开源

    Activiti

    JBPM 

    Flowable

    开源

    免费

    开发工作量大

    开发难度大

    中文支持不好

    Activiti

    相对JBPM上手容易

    原生支持Spring

    与 Spring boot 集成较好

    Flowable新出的,使用人数少教程资源少

    商用

    炎黄盈动

    普元

    慧正

    天翎

    宏天

    开发工作量小

    开发难度小

    符合中国国情

    闭源

    价格高

       

    二、核心7大接口、28张表

    (一)7大接口

    • RepositoryService:提供一系列管理流程部署和流程定义的API。
    • RuntimeService:在流程运行时对流程实例进行管理与控制。
    • TaskService:对流程任务进行管理,例如任务提醒、任务完成和创建任务等。
    • IdentityService:提供对流程角色数据进行管理的API,这些角色数据包括用户组、用户及它们之间的关系。
    • ManagementService:提供对流程引擎进行管理和维护的服务。
    • HistoryService:对流程的历史数据进行操作,包括查询、删除这些历史数据。
    • FormService:表单服务。

    (二)28张表

    1. act_ge_ 通用数据表,ge是general的缩写
    2. act_hi_ 历史数据表,hi是history的缩写,对应HistoryService接口
    3. act_id_ 身份数据表,id是identity的缩写,对应IdentityService接口
    4. act_re_ 流程存储表,re是repository的缩写,对应RepositoryService接口,存储流程部署和流程定义等静态数据
    5. act_ru_ 运行时数据表,ru是runtime的缩写,对应RuntimeService接口和TaskService接口,存储流程实例和用户任务等动态数据

    表结构操作: 
    3.3.1:资源库流程规则表 

    • 1) act_re_deployment 部署信息表 
    • 2) act_re_model 流程设计模型部署表 
    • 3) act_re_procdef 流程定义数据表 

    3.3.2:运行时数据库表 

    • 1) act_ru_execution 运行时流程执行实例表 
    • 2) act_ru_identitylink 运行时流程人员表,主要存储任务节点与参与者的相关信息 
    • 3) act_ru_task 运行时任务节点表 
    • 4) act_ru_variable 运行时流程变量数据表 

    3.3.3:历史数据库表 

    • 1) act_hi_actinst 历史节点表 
    • 2) act_hi_attachment 历史附件表 
    • 3) act_ih_comment 历史意见表 
    • 4) act_hi_identitylink 历史流程人员表 
    • 5) act_hi_detail 历史详情表,提供历史变量的查询 
    • 6) act_hi_procinst 历史流程实例表 
    • 7) act_hi_taskinst 历史任务实例表 
    • 8) act_hi_varinst 历史变量表 

    3.3.4:组织机构表 

    • 1) act_id_group 用户组信息表 
    • 2) act_id_info 用户扩展信息表 
    • 3) act_id_membership 用户与用户组对应信息表 
    • 4) act_id_user 用户信息表 

    这四张表很常见,基本的组织机构管理,关于用户认证方面建议还是自己开发一套,组件自带的功能太简单,使用中有很多需求难以满足 
    3.3.5:通用数据表 

    • 1) act_ge_bytearray 二进制数据表 
    • 2) act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录, 
    • 3.4:activiti.cfg.xml(activiti的配置文件) 

    Activiti核心配置文件,配置流程引擎创建工具的基本参数和数据库连接池参数。 
    定义数据库配置参数: 

    • jdbcUrl: 数据库的JDBC URL。 
    • jdbcDriver: 对应不同数据库类型的驱动。 
    • jdbcUsername: 连接数据库的用户名。 
    • jdbcPassword: 连接数据库的密码。 

    基于JDBC参数配置的数据库连接 会使用默认的MyBatis连接池。 下面的参数可以用来配置连接池(来自MyBatis参数): 

    • jdbcMaxActiveConnections: 连接池中处于被使用状态的连接的最大值。默认为10。 
    • jdbcMaxIdleConnections: 连接池中处于空闲状态的连接的最大值。 
    • jdbcMaxCheckoutTime: 连接被取出使用的最长时间,超过时间会被强制回收。 默认为20000(20秒)。 
    • jdbcMaxWaitTime: 这是一个底层配置,让连接池可以在长时间无法获得连接时, 打印一条日志,并重新尝试获取一个连接。(避免因为错误配置导致沉默的操作失败)。 默认为20000(20秒)。

     流程部署相关表 

    • act_re_deployement 部署对象表 
    • act_rep_procdef  流程定义表 
    • act_ge_bytearray 资源文件表 
    • act_ge_prperty  主键生成策略表(对于部署对象表的主键ID)

     流程实例相关表

    •  act_ru_execution 正在执行的执行对象表(包含执行对象ID和流程实例ID,如果有多个线程可能流程实例ID不一样)
    •  act_hi_procinst 流程实例历史表
    •  act_hi_actinst 存放历史所有完成的任务

     Task 任务相关表

    •  act_ru_task 代办任务表 (只对应节点是UserTask的)
    •  act_hi_taskinst 代办任务历史表 (只对应节点是UserTask的) 
    •  act_hi_actinst  所有节点活动历史表 (对应流程的所有节点的活动历史,从开始节点一直到结束节点中间的所有节点的活动都会被记录)

    流程变量表

    •  act_ru_variable 正在执行的流程变量表
    •  act_hi_variable 流程变量历史表

     三、创建BPMN业务流程模型

    1.将Activiti提供的流程设计器应用activiti-app.war部署到Tomcat的webapps目录。
    2.创建新的MySql数据库。修改activiti-appWEB-INFclassesMETA-INFactiviti-app目录下的activiti-app.properties配置文件,默认使用H2内存数据库,创建的模型重启后会丢失,改成使用MySql数据库。
    3.浏览器访问http://localhost:8080/activiti-app,登录账户:admin:test
    4.创建一个请假审批流程图

    给每个用户任务指派候选组(有权限执行当前任务的角色)


    指派候选组

    排他网关设置条件分支表达式


    5.导出流程图为.bpmn20.xml文件


    导出xml文件

    四、Spring Boot与Activiti 6.0整合

    1.在POM文件中添加依赖

    1.  
      <dependency>
    2.  
          <groupId>org.activiti</groupId>
    3.  
          <artifactId>activiti-spring-boot-starter-basic</artifactId>
    4.  
          <version>6.0.0</version>
    5.  
      </dependency>

    2.将导出的.bpmn20.xml文件拷贝到项目文件夹/resources/processes下
    3.application.properties文件添加配置项

    spring.activiti.database-schema-update=true

    databaseSchemaUpdate配置项可以设置流程引擎启动和关闭时数据库执行的策略。 databaseSchemaUpdate有以下四个值:

    • false:false为默认值,设置为该值后,Activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配时,将在启动时抛出异常。
    • true:设置为该值后,Activiti会对数据库中所有的表进行更新,如果表不存在,则Activiti会自动创建。
    • create-drop:Activiti启动时,会执行数据库表的创建操作,在Activiti关闭时,执行数据库表的删除操作。
    • drop-create:Activiti启动时,执行数据库表的删除操作在Activiti关闭时,会执行数据库表的创建操作。

    4.启动应用,会在数据库里创建28张表,表创建好之后停止应用。application.properties文件修改配置项

    1.  
      #每次应用启动不检查Activiti数据表是否存在及版本号是否匹配,提升应用启动速度
    2.  
      spring.activiti.database-schema-update=false

    5.application.properties文件增加配置项

    1.  
      #保存历史数据级别设置为full最高级别,便于历史数据的追溯
    2.  
      spring.activiti.history-level=full

    对于历史数据,保存到何种粒度,Activiti提供了history-level属性对其进行配置。history-level属性有点像log4j的日志输出级别,该属性有以下四个值:

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

    6.完成以上步骤,就可以在程序中使用自动注入的方式,使用Activiti的7大接口。

    1.  
      @Autowired
    2.  
      private RuntimeService runtimeService;
    3.  
       
    4.  
      @Autowired
    5.  
      private TaskService taskService;
    6.  
       
    7.  
      @Autowired
    8.  
      private IdentityService identityService;
    9.  
       
    10.  
      @Autowired
    11.  
      private RepositoryService repositoryService;
    12.  
       
    13.  
      @Autowired
    14.  
      private ProcessEngine processEngine;
    15.  
       
    16.  
      @Autowired
    17.  
      private HistoryService historyService;
    1.  
      5:核心API 
    2.  
      5.1:ProcessEngine 
    3.  
      说明: 
    4.  
      1) 在Activiti中最核心的类,其他的类都是由他而来。 
    5.  
      2) 产生方式:
    6.  
       
    7.  
      在前面看到了两种创建ProcessEngine(流程引擎)的方式,而这里要简化很多,调用ProcessEngines的getDefaultProceeEngine方法时会自动加载classpath下名为activiti.cfg.xml文件。 
    8.  
      3) 可以产生RepositoryService
    9.  
       
    10.  
      4) 可以产生RuntimeService
    11.  
       
    12.  
      5) 可以产生TaskService
    13.  
       
    14.  
      各个Service的作用: 
    15.  
      RepositoryService 管理流程定义 
    16.  
      RuntimeService 执行管理,包括启动、推进、删除流程实例等操作 
    17.  
      TaskService 任务管理 
    18.  
      HistoryService 历史管理(执行完的数据的管理) 
    19.  
      IdentityService 组织机构管理 
    20.  
      FormService 一个可选服务,任务表单管理 
    21.  
      ManagerService
    22.  
       
    23.  
      5.2:RepositoryService 
    24.  
      是Activiti的仓库服务类。所谓的仓库指流程定义文档的两个文件:bpmn文件和流程图片。 
    25.  
      1) 产生方式
    26.  
       
    27.  
      2) 可以产生DeploymentBuilder,用来定义流程部署的相关参数
    28.  
       
    29.  
      3) 删除流程定义
    30.  
       
    31.  
      5.3:RuntimeService 
    32.  
      是activiti的流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。 
    33.  
      5.4:TaskService 
    34.  
      是activiti的任务服务类。可以从这个类中获取任务的信息。 
    35.  
      5.5:HistoryService 
    36.  
      是activiti的查询历史信息的类。在一个流程执行完成后,这个对象为我们提供查询历史信息。 
    37.  
      5.6:ProcessDefinition 
    38.  
      流程定义类。可以从这里获得资源文件等。 
    39.  
      5.7:ProcessInstance 
    40.  
      代表流程定义的执行实例。如范冰冰请了一天的假,她就必须发出一个流程实例的申请。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个。 
    41.  
      5.8:Execution 
    42.  
      Activiti用这个对象去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。 

    1.  
      RepositoryService:管理流程定义
    2.  
       
    3.  
      RuntimeService:执行管理,包括启动、推进、删除流程实例等操作
    4.  
       
    5.  
      TaskService:任务管理
    6.  
       
    7.  
      HistoryService:历史管理(执行完的数据的管理)
    8.  
       
    9.  
      IdentityService:组织机构管理
    10.  
       
    11.  
      FormService:一个可选服务,任务表单管理
    12.  
       
    13.  
      ManagerService
    14.  
       
    15.  
      5.2:RepositoryService
    16.  
      是Activiti的仓库服务类。所谓的仓库指流程定义文档的两个文件:bpmn文件和流程图片。
    17.  
       
    18.  
      1产生方式
    19.  
        
    20.  
      2可以产生DeploymentBuilder,用来定义流程部署的相关参数
    21.  
         
    22.  
      3删除流程定义
    23.  
        
    24.  
      5.3:RuntimeService
    25.  
      是activiti的流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。
    26.  
        
    27.  
      5.4:TaskService
    28.  
      是activiti的任务服务类。可以从这个类中获取任务的信息。
    29.  
       
    30.  
      5.5:HistoryService
    31.  
      是activiti的查询历史信息的类。在一个流程执行完成后,这个对象为我们提供查询历史信息。
    32.  
       
    33.  
      5.6:ProcessDefinition
    34.  
      流程定义类。可以从这里获得资源文件等。
    35.  
       
    36.  
      5.7:ProcessInstance
    37.  
      代表流程定义的执行实例。如范冰冰请了一天的假,她就必须发出一个流程实例的申请。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个。
    38.  
       
    39.  
      5.8:Execution
    40.  
      Activiti用这个对象去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。

     
    五、项目中的用户、角色与Activiti中的用户、用户组整合

    每个项目都有自己的用户、角色表,Activiti也有自己的用户、用户组表。因此项目中的用户、角色与Activiti中的用户、用户组要做整合。

    1.  
      //项目中每创建一个新用户,对应的要创建一个Activiti用户
    2.  
      //两者的userId和userName一致
    3.  
      User admin=identityService.newUser("1");
    4.  
      admin.setLastName("admin");
    5.  
      identityService.saveUser(admin);
    6.  
       
    7.  
      //项目中每创建一个角色,对应的要创建一个Activiti用户组
    8.  
      Group adminGroup=identityService.newGroup("1");
    9.  
      adminGroup.setName("admin");
    10.  
      identityService.saveGroup(adminGroup);
    11.  
       
    12.  
      //用户与用户组关系绑定
    13.  
      identityService.createMembership("1","1");

    六、请假审批流程

    1.请假申请和请假审批数据库表设计
    表设计原则:流程数据和业务数据相分离。Activiti相关表只负责流程的跳转、走向等。流程中产生的业务表单数据、审批意见、附件等存储在开发人员定义的业务表中。流程数据和业务数据之间通过processInstanceId(流程实例ID)和业务数据主键相互关联。

    为什么不使用Activiti相关表来存储表单数据和附件?

    activiti参数表

    Activiti为了应用的灵活性和通用性采用了纵表的方式存储表单数据。假设一条请假申请表单数据有10个字段,那就需要10条记录存储原本横表只需要一条记录存储的数据。采用纵表的方式会有如下问题:

    会有大量的冗余数据并且数据量会急剧的增长
    查询语句复杂,查询效率低
    尤其不适合做后期的统计报表分析


    activiti附件表

    Activiti存储附件使用Blob数据格式,文件存储在数据库里,数据库的数据文件会变得超大,不利于数据库备份和迁移。
    请假申请表结构

    请假申请表

    请假审批表结构

    请假审批表


    2.填写请假申请表单,启动流程实例

    填写请假申请

    1.  
      //启动流程实例,字符串"vacation"是BPMN模型文件里process元素的id
    2.  
      ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("vacation");
    3.  
      //流程实例启动后,流程会跳转到请假申请节点
    4.  
      Task vacationApply = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
    5.  
      //设置请假申请任务的执行人
    6.  
      taskService.setAssignee(vacationApply.getId(), req.getUserId().toString());
    7.  
       
    8.  
      //设置流程参数:请假天数和表单ID
    9.  
      //流程引擎会根据请假天数days>3判断流程走向
    10.  
      //formId是用来将流程数据和表单数据关联起来
    11.  
      Map<String, Object> args = new HashMap<>();
    12.  
      args.put("days", req.getDays());
    13.  
      args.put("formId", formId);
    14.  
       
    15.  
      //完成请假申请任务
    16.  
      taskService.complete(vacationApply.getId(), args);


    3.待审批列表

    1.  
      //查出当前登录用户所在的用户组
    2.  
      List<Group> groups = identityService.createGroupQuery()
    3.  
              .groupMember(String.valueOf(userId)).list();
    4.  
      List<String> groupNames = groups.stream()
    5.  
              .map(group -> group.getName()).collect(Collectors.toList());
    6.  
       
    7.  
      //查询用户组的待审批请假流程列表
    8.  
      List<Task> tasks = taskService.createTaskQuery()
    9.  
              .processDefinitionKey("vacation")
    10.  
              .taskCandidateGroupIn(groupNames)
    11.  
              .listPage(pageNum - 1, pageSize);
    12.  
       
    13.  
      //根据流程实例ID查询请假申请表单数据
    14.  
      List<String> processInstanceIds = tasks.stream()
    15.  
              .map(task -> task.getProcessInstanceId())
    16.  
              .collect(Collectors.toList());
    17.  
      List<VacationApplyBasicPO> vacationApplyList = 
    18.  
              vacationRepository.getVacationApplyList(processInstanceIds);


    4.请假审批功能

    1.  
      //查询当前审批节点
    2.  
      Task vacationAudit = taskService.createTaskQuery()
    3.  
              .taskId(req.getTaskId()).singleResult();
    4.  
       
    5.  
      if (req.getAuditResult() == 1) {//审批通过
    6.  
          //设置流程参数:审批ID
    7.  
          Map<String, Object> args = new HashMap<>();
    8.  
          args.put("auditId", auditId);
    9.  
       
    10.  
          //设置审批任务的执行人
    11.  
          taskService.claim(vacationAudit.getId(), req.getUserId().toString());
    12.  
          //完成审批任务
    13.  
          taskService.complete(vacationAudit.getId(), args);
    14.  
      } else {
    15.  
          //审批不通过,结束流程
    16.  
          runtimeService.deleteProcessInstance(vacationAudit.getProcessInstanceId(), auditId);
    17.  
      }


    5.查看流程图功能

    1.  
      //controller层代码
    2.  
      @RequestMapping(value = "/image", method = RequestMethod.GET)
    3.  
      public void image(HttpServletResponse response,
    4.  
       @RequestParam String processInstanceId) {
    5.  
          try {
    6.  
              InputStream is = vacationService.getDiagram(processInstanceId);
    7.  
              if (is == null)
    8.  
                  return;
    9.  
       
    10.  
              response.setContentType("image/png");
    11.  
       
    12.  
              BufferedImage image = ImageIO.read(is);
    13.  
              OutputStream out = response.getOutputStream();
    14.  
              ImageIO.write(image, "png", out);
    15.  
       
    16.  
              is.close();
    17.  
              out.close();
    18.  
          } catch (Exception ex) {
    19.  
              logger.error("查看流程图失败", ex);
    20.  
          }
    21.  
      }
    22.  
       
    23.  
      //service层代码
    24.  
      @Override
    25.  
      public InputStream getDiagram(String processInstanceId) {
    26.  
          //获得流程实例
    27.  
          ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
    28.  
                  .processInstanceId(processInstanceId).singleResult();
    29.  
          String processDefinitionId = StringUtils.EMPTY;
    30.  
          if (processInstance == null) {
    31.  
              //查询已经结束的流程实例
    32.  
              HistoricProcessInstance processInstanceHistory =
    33.  
                      historyService.createHistoricProcessInstanceQuery()
    34.  
                              .processInstanceId(processInstanceId).singleResult();
    35.  
              if (processInstanceHistory == null)
    36.  
                  return null;
    37.  
              else
    38.  
                  processDefinitionId = processInstanceHistory.getProcessDefinitionId();
    39.  
          } else {
    40.  
              processDefinitionId = processInstance.getProcessDefinitionId();
    41.  
          }
    42.  
       
    43.  
          //使用宋体
    44.  
          String fontName = "宋体";
    45.  
          //获取BPMN模型对象
    46.  
          BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
    47.  
          //获取流程实例当前的节点,需要高亮显示
    48.  
          List<String> currentActs = Collections.EMPTY_LIST;
    49.  
          if (processInstance != null)
    50.  
              currentActs = runtimeService.getActiveActivityIds(processInstance.getId());
    51.  
       
    52.  
          return processEngine.getProcessEngineConfiguration()
    53.  
                  .getProcessDiagramGenerator()
    54.  
                  .generateDiagram(model, "png", currentActs, new ArrayList<String>(),
    55.  
                          fontName, fontName, fontName, null, 1.0);
    56.  
      }


     参照教程:https://blog.csdn.net/qq877507054/article/details/60143099

  • 相关阅读:
    [51nod1299]监狱逃离
    [51nod1206]Picture
    noi 2016 游记
    [Codeforces 696D] Legen...
    [bzoj2574] [Poi1999]Store-Keeper
    [bzoj1227] [SDOI2009]虔诚的墓主人
    [bzoj3979] [WF2012]infiltration
    Docker
    SpringBoot实现登录
    SpringBoot第一次案例
  • 原文地址:https://www.cnblogs.com/sea520/p/13646780.html
Copyright © 2011-2022 走看看