• Activiti工作流学习分享


    一:什么是Activiti

    Activiti是一个开源的工作流引擎,它实现了BPMN 2.0规范,可以发布设计好的流程定义,并通过api进行流程调度。

    业务流程模型注解(Business Process Modeling Notation - BPMN)是 业务流程模型的一种标准图形注解。包括用户任务,定时任务都有统一的模型规范。

    Activiti 作为一个遵从 Apache 许可的工作流和业务流程管理开源平台,其核心是基于Java的超快速、超稳定的 BPMN2.0 流程引擎,强调流程服务的可嵌入性和可扩展性,同时更加强调面向业务人员。

    在项目中,Activiti实际上相当于一个第三方插件帮助原本系统业务更好的执行,Activiti本身并没有任何业务逻辑。

    二:为什么需要引入Activiti工作流

    举个例子:

    如果我们要开发一套请假流程,具体流程如下:
    在这里插入图片描述
    在没有Activiti工作流引擎帮助下,我们会怎么设计表结构?默认模式下,应该会设计两张表,一张来存请假内容,一张来存请假审批过程。只有总经理和HR人力能够批改。假设当我们设计好表后,需求改变了,经理审批这个节点改成组长审批,那这个时候,我们是不是又要修改代码或者表结构?

    这个时候Activiti引擎起作用。我们不会把具体节点人写死,而是可以在流程过程中指定。

    三:如何使用Activiti

    Activiti使用时注意的概念
    1.保存流程图—>相当于将流程图存到activiti数据库中,此时是静态资源。

    2.发布流程---->相当java中的类,如果开始节点部署的普通的开始事件,则不会自动启动流程,如果里面开始节点使用定时事件,则到时间便会自动启动流程实例(可以内置定时事件应用到TCL电子的点检任务)。

    3.启动流程实例—>相当java中的对象

    1.每个节点的任务都指定具体人

    在这里插入图片描述

    在这里插入图片描述

    /**

    • 保存流程

    • @param modelId 模型ID

    • @param name 流程模型名称

    • @param description

    • @param json_xml 流程文件

    • @param svg_xml 图片
      */
      @RequestMapping(value="/model/{modelId}/save", method = RequestMethod.PUT)
      @ResponseStatus(value = HttpStatus.OK)
      public void saveModel(@PathVariable String modelId
      , String name, String description
      , String json_xml, String svg_xml) {
      try {

      Model model = repositoryService.getModel(modelId);

      ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());

      modelJson.put(MODEL_NAME, name);
      modelJson.put(MODEL_DESCRIPTION, description);
      model.setMetaInfo(modelJson.toString());
      model.setName(name);
      repositoryService.saveModel(model);

      repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes(“utf-8”));

      InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes(“utf-8”));
      TranscoderInput input = new TranscoderInput(svgStream);

      PNGTranscoder transcoder = new PNGTranscoder();
      // Setup output
      ByteArrayOutputStream outStream = new ByteArrayOutputStream();
      TranscoderOutput output = new TranscoderOutput(outStream);

      // Do the transformation
      transcoder.transcode(input, output);
      final byte[] result = outStream.toByteArray();
      repositoryService.addModelEditorSourceExtra(model.getId(), result);
      outStream.close();
      } catch (Exception e) {
      LOGGER.error(“Error saving model”, e);
      throw new ActivitiException(“Error saving model”, e);
      }
      }

    /**
    * 发布流程
    * @param modelId 模型ID
    * @return
    */
    @ResponseBody
    @RequestMapping("/publish")
    public Object publish(String modelId){
    logger.info(“流程部署入参modelId:{}”,modelId);
    Map<String, String> map = new HashMap<String, String>();
    try {
    Model modelData = repositoryService.getModel(modelId);
    byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
    if (bytes == null) {
    logger.info(“部署ID:{}的模型数据为空,请先设计流程并成功保存,再进行发布”,modelId);
    map.put(“code”, “FAILURE”);
    return map;
    }
    JsonNode modelNode = new ObjectMapper().readTree(bytes);
    BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
    Deployment deployment = repositoryService.createDeployment()
    .name(modelData.getName())
    .addBpmnModel(modelData.getKey()+".bpmn20.xml", model)
    .deploy();
    modelData.setDeploymentId(deployment.getId());
    repositoryService.saveModel(modelData);
    map.put(“code”, “SUCCESS”);
    } catch (Exception e) {
    logger.info(“部署modelId:{}模型服务异常:{}”,modelId,e);
    map.put(“code”, “FAILURE”);
    }
    logger.info(“流程部署出参map:{}”,map);
    return map;
    }

    在这里插入图片描述

    /**

    • 启动流程实例
      /
      @Test
      public void startProcessInstance() {
      ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(“process”);
      }
      /
      *

    • 完成Task任务需在最后执行
      */
      @Test
      public void completeTask() {

      List list = taskService.createTaskQuery().taskAssignee(“张三”).list();

      for (Task task : list) {
      taskService.complete(task.getId());
      }

    }

    2.节点代理人是动态的

    在这里插入图片描述

    流程变量概念:相当于局部变量,使用范围在当前实例内有效

    /**

    • 启动流程实例
      */
      @Test
      public void startProcessInstance() {
      Map<String, Object> map = new HashMap<>();
      map.put(“name”, “张三”);
      runtimeService.startProcessInstanceByKey(“process”,map);

    }

    3.流程分支控制

    在这里插入图片描述

    在这里插入图片描述

    /**

    • 完成任务设置流程变量 方式一
      */
      @Test
      public void completeTask() {

      List list = taskService.createTaskQuery().taskAssignee(“张三”).list();

      for (Task task : list) {
      taskService.setVariable(task.getId(),“num”,2);
      taskService.complete(task.getId());
      }

    }

    /**

    • 完成任务设置流程变量 方式二
      */
      @Test
      public void completeTask() {

      List list = taskService.createTaskQuery().taskAssignee(“张三”).list();

      for (Task task : list) {
      Map<String, Object> map = new HashMap<>();
      map.put(“num”, 2);
      taskService.complete(task.getId(),map);
      }

    }

    4.候选人和候选组
    在实现上,候选人和候选组是一样的

    假设总经理有多个人可以审批请假流程,那我们不能把审批人固定为某个人。我们可以直接写死候选人,也可以将候选人设置为流程变量,然后在流程执行过程中设置变量值。
    在这里插入图片描述

    在这里插入图片描述

    @Test
    public void claimTask() {
    List list = taskService.createTaskQuery().taskCandidateUser(“刘备”).list();

       for (Task task : list) {
           taskService.claim(task.getId(), "刘备");
       }
    
    • 1
    • 2
    • 3

    }

    5.定时任务和脚本任务
    假设总经理比较忙,太长时间忘记审批,这个时候可以设置定时任务,调用脚本进行通知
    在这里插入图片描述

    定时任务设置

    在这里插入图片描述

    时间格式使用ISO-8601使用方式可以参考百度百科;其中循环时间可以使用corn表达式

    脚本任务设置
    在这里插入图片描述

    脚本支持JavaScript, groovy,研究当中,使用JavaScript

    脚本内容中我们可以调用java后台代码中方法

    如下callService是我们在java后台中写的一个托管给spring的类,execution是activiti内置的对象,javascript和java代码中都能对其进行调用,可以通过execution获取该流程当前实例id,流程变量等。

    在这里插入图片描述

    @Component
    public class CallService {

    public String get(DelegateExecution execution){
        System.out.println("----get----"+new Date()+"processInstanceId="+execution.getProcessInstanceId()+"--businessKey="+execution.getProcessBusinessKey());
        return null;
    }
    
    • 1
    • 2
    • 3
    • 4

    }

    6.内置定时启动事件
    应用场景:需要定时启动某些流程的时候,我们可以使用定时启动事件做为开始事件。

    此时只需要将此流程部署即可,注意点:如果需要使用该定时启动事件的流程来定时启动任务,则部署该定时启动事件流程时需要设置不同流程名(processDefinitonKey)。

    和前端探讨:1.修改节点内容

    在这里插入图片描述

    四.Activiti架构

    在这里插入图片描述
    activiti.cfg.xml

    activiti 的引擎配置文件,包括:ProcessEngineConfiguration 的定义、数据源定义、事务管理器等,此文件其实就是一个 spring 配置文件。

    ProcessEngineConfiguration

    流程引擎的配置类,通过 ProcessEngineConfiguration 可以创建工作流引擎 ProceccEngine。

    ProcessEngine

    工作流引擎,相当于一个门面接口,通过 ProcessEngineConfiguration 创建 processEngine,通过ProcessEngine 创建各个 service 接口。

    7个service,在研究当中只看

    IdentityService, FormService,ManagementService暂无研究

    RepositoryService

    是 activiti 的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此 service 将流程定义文件的内容部署到计算机。

    除了部署流程定义以外还可以:

    查询引擎中的发布包和流程定义。

    暂停或激活发布包,对应全部和特定流程定义。 暂停意味着它们不能再执行任何操作了,激活

    是对应的反向操作。

    获得多种资源,像是包含在发布包里的文件, 或引擎自动生成的流程图。

    获得流程定义的 pojo 版本, 可以用来通过 java 解析流程,而不必通过 xml。

    RuntimeService

    它是 activiti 的流程运行管理类。可以从这个服务类中获取很多关于流程执行相关的信息

    TaskService

    是 activiti 的任务管理类。可以从这个类中获取任务的信息。

    HistoryService

    是 activiti 的历史管理类,可以查询历史信息,执行流程时,引擎会保存很多数据(根据配置),比

    如流程实例启动时间,任务的参与者, 完成任务的时间,每个流程实例的执行路径,等等。 这个

    服务主要通过查询功能来获得这些数据。

    https://blog.csdn.net/sinat_36759535/article/details/108110928

  • 相关阅读:
    测试开发题目整理(二)
    测试开发题目整理(一)
    Python + request接口测试中Cookie和Session的获取和使用
    requests发送HTTPS请求(处理SSL证书验证)
    js ES5面向对象继承 模仿ES6
    如何使用canvas绘制椭圆,扩展非chrome浏览器中的ellipse方法
    javascript对象创建及继承
    观察者模式及事件与委托的区别-20171215内训会
    html5悬浮球效果
    文本框高度自适应不出滚动条
  • 原文地址:https://www.cnblogs.com/yuluoxingkong/p/14187910.html
Copyright © 2020-2023  润新知