Activiti7流程操作详解

news2025/4/6 1:50:20

一、Activiti流程操作步骤

  • 定义流程,按照BPMN的规范,使用流程定义工具,用流程符号把整个流程描述出来

  • 部署流程,把画好的流程定义文件,加载到数据库中,生成表的数据

  • 启动流程,使用java代码来操作数据库表中的内容

  • 操作流程当中的各个任务

通过以上三步、就可以创建一个Activiti工作流、并且启动该流程。

二、常见流程符号

2.1 BPMN 2.0

BPMNBusiness Process Model AndNotation)- 业务流程模型和符号 是由BPMIBusinessProcess Management Initiative)开发的一套标准的业务流程建模符号,使用BPMN提供的符号可以创建业务流程。

BPMN 是目前被各 BPM 厂商广泛接受的 BPM 标准。

Activiti 就是使用 BPMN 2.0 进行流程建模、流程执行管理等。

BPMN的五类元素:

类别对象
流对象 (Flow Objects )事件( Events)、活动 (Activities )、网关 ( Gateways )
数据 (Data)数据对象 ( Data Objects )、数据输入 ( Data Inputs )、数据输出( Data Outputs )、数据存储 ( Data Stores )
连接对象 (Connecting Objects )顺序流 ( Sequence Flows )、消息流 ( Message Flows )、关联 ( Associations )、数据关联( Data Associations )
泳道(Swimlanes)池子( Pools)、泳道 ( Lanes)
工件 ( Artifacts )组 (Group )、文字注释

2.2 常用流程符号

1)事件 Event

  • 开始事件

在这里插入图片描述

  • 中间事件

在这里插入图片描述
在这里插入图片描述

  • 结束事件

在这里插入图片描述

2)活动 Activity

活动是工作或任务的一个通用术语。一个活动可以是一个任务,还可以是一个当前流程的子处理流程; 其次,你还可以为活动指定不同的类型。常见活动如下:
在这里插入图片描述

3)网关 GateWay

网关用来处理决策,有几种常用网关需要了解:
在这里插入图片描述

4)流向 Flow

流是连接两个流程节点的连线。常见的流向包含以下几种:

在这里插入图片描述

三、安装Activiti BPMN visualizer插件

这个在idea2020版本开始,老的插件actiBPM已经在插件市场中搜索不到了。

虽然依旧可以在插件官网下载actiBPM到本地进行安装,但是没必要,新的插件更好使用一些。
在这里插入图片描述

四、流程设计器使用

4.1 新建BPMN 2.0文件

在这里插入图片描述
新建以后会得到一个XML文件,并没有出现画BPMN流程图的界面。
在这里插入图片描述

4.2 调出流程设计页面

在这里插入图片描述
在这里插入图片描述

4.3 绘制出差流程

1)绘制开始事件

右击流程设计页面,选择Start events
在这里插入图片描述

选择后注意下面三个区域即可:
在这里插入图片描述

2)绘制用户任务流程

  • 创建申请单
    在这里插入图片描述

绘制出用户任务之后,可以指定流程名称为创建出差申请,并且指定分配到任务的人为小王。
在这里插入图片描述

  • 部门经理审批

在这里插入图片描述

  • 总经理审批

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XblAWfMu-1683250543424)(assets\流程-部门经理审批.png)]
在这里插入图片描述

  • 财务审批
    在这里插入图片描述

3)绘制结束事件

在这里插入图片描述
在这里插入图片描述

4)绘制流向

1.选中流程节点

在这里插入图片描述

2.鼠标左键按住右上角箭头进行拖动

拖向需要指向的节点即可。
流向-拖动指向

3.最终流程图效果

在这里插入图片描述

五、流程操作

5.1 流程定义

流程定义是线下按照bpmn2.0标准去描述 业务流程,通常使用idea中的插件对业务流程进行建模。

使用idea下的designer设计器绘制流程,需要成两个文件:.bpmn.png

1)bpmn文件

已经按第三步的操作定义完成,在就是first.bpmn.xml文件。

2)png文件

直接在流程设计器中,右击后再菜单栏点击Save to PNG,然后选择文件位置,放到.bpmn文件的相同目录下即可。
在这里插入图片描述

5.2 流程部署

1)单文件部署方式

将上面在设计器中定义的流程部署到activiti数据库中,就是流程定义部署。

直观的说就是把bpmn文件定义的流程和png文件存储到数据库当中。

这里使用一个单元测试来进行演示:

/**
  * 部署流程定义测试
  */
@Test
public void DeployTest() {
    // 1. 创建ProcessEngine流程引擎对象
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2、得到RepositoryService实例
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 3、使用RepositoryService进行部署,定义一个流程名字,把bpmn和png部署到数据库中
    Deployment deployment = repositoryService.createDeployment()    // 创建一个部署流程
        .name("出差申请流程")                                 	// 给部署流程命名
        .addClasspathResource("a-bpmn/first.bpmn20.xml")    	// 添加类路径下的资源文件
        .addClasspathResource("a-bpmn/first.png")
        .deploy();												// 执行流程部署
    // 4、输出部署信息
    System.out.println("流程部署id:" + deployment.getId());
    System.out.println("流程部署名称:" + deployment.getName());
}

运行之后,activiti主要操作了4张表:

  • act_re_deployment :流程部署表,每部署一个流程就会多一条数据
    在这里插入图片描述

  • act_re_procdef:流程定义表
    在这里插入图片描述

    这里面比较重要的字段:

    • KTY_:也就是之前流程定义时的ID属性
    • RESOURCE_NAME_bpmn文件的资源路径
    • DGRM_RESOURCE_NAME_png文件的资源路径
  • act_ge_bytearray :通用的流程资源表
    在这里插入图片描述

    • 查看图像的方法:用Navicat的话选择开始事务旁边的下拉框为图像,再选中想看的png文件,下方就能显示了
      在这里插入图片描述

    • 查看bpmn文件的方法
      在这里插入图片描述

    其实这就是一个xml文件即可。

  • act_ge_property:系统相关属性
    在这里插入图片描述

完成上述操作后Activiti会将上边代码中指定的bpmn文件和图片文件保存在Activiti数据库中的相关表中。

小结:

act_re_deploymentact_re_procdef一对多关系.

一次部署在流程部署表生成一条记录,但一次部署可以部署多个流程定义,每个流程定义在流程定义表生成一条记录。

每一个流程定义在act_ge_bytearray会存在两个资源记录,bpmnpng

建议:

一次部署一个流程,这样部署表和流程定义表是一对一有关系,方便读取流程部署及流程定义信息。

2)压缩包部署方式

这种方式需要把bpmn文件和png文件打成一个.zip的压缩包。

/**
  * 部署流程--压缩包部署方式
  */
@Test
public void deployByZipTest() {
    // 1. 创建ProcessEngine流程引擎对象
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2.定义字节输入流
    InputStream inputStream = this.getClass()
        .getClassLoader()
        .getResourceAsStream("bpmn/evection.zip");
    ZipInputStream zipInputStream = new ZipInputStream(inputStream);
    // 3.获取repositoryService
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 4.流程部署
    Deployment deployment = repositoryService.createDeployment().addZipInputStream(zipInputStream).deploy();
    // 5、输出部署信息
    System.out.println("流程部署id:" + deployment.getId());
    System.out.println("流程部署名称:" + deployment.getName());
}

当有很多流程的时候,很多时候都是使用这种压缩包的形式来进行流程的部署

前端直接把这个压缩包上传上来,后端拿到后,进行流程部署即可。

5.3 启动流程实例

/**
  * 启动流程实例
  */
@Test
public void startProcessTest(){
    // 1、创建ProcessEngine
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2、获取RunTimeService
    RuntimeService runtimeService = processEngine.getRuntimeService();
    // 3、根据流程定义Id启动流程,并获取流程实例
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myEvection");
    // 输出内容
    System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
    System.out.println("流程实例id:" + processInstance.getId());
    System.out.println("当前活动Id:" + processInstance.getActivityId());
}

所操作数据表如下:

  • act_hi_actinst :流程实例执行历史
    在这里插入图片描述

  • act_hi_identitylink :流程的参与用户历史信息
    在这里插入图片描述

  • act_hi_procinst :流程实例历史信息
    在这里插入图片描述

  • act_hi_taskinst : 流程任务历史信息
    在这里插入图片描述

  • act_ru_execution:流程执行信息
    在这里插入图片描述

  • act_ru_identitylink :流程的参与用户信息,记录当前用户需要做的流程实例的关联关系
    在这里插入图片描述

  • act_ru_task :任务信息
    在这里插入图片描述

5.4 流程任务查询

一个流程启动后,任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。

/**
  * 查询当前个人待执行的任务
  */
@Test
public void findTaskListTest() {
    // 1.创建流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2.获取TaskService
    TaskService taskService = processEngine.getTaskService();
    // 3.根据流程key 和 任务负责人 查询任务
    String assignee = "小王";
    List<Task> list = taskService.createTaskQuery()
        .processDefinitionKey("myEvection")     	//流程Key
        .taskAssignee(assignee)                 	//只查询当前任务负责人的任务
        .list();

    list.forEach(task -> {
        System.out.printf("-----------------------------------------");
        System.out.println("流程实例id:" + task.getProcessInstanceId());
        System.out.println("任务id:" + task.getId());
        System.out.println("任务负责人:" + task.getAssignee());
        System.out.println("任务名称:" + task.getName());
    });
}

执行上述代码后,就可以查询出来小王的所有待办任务了:
在这里插入图片描述

5.5 流程任务处理

任务负责人查询属于自己的待办任务,选择相应的任务进行处理,并且去完成自己的代办任务。

/**
  * 完成个人代办任务
  */
@Test
public void completTaskTest(){
    // 1.创建流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2. 获取TaskService实例
    TaskService taskService = processEngine.getTaskService();
    // 3.根据流程key 和 任务的负责人 查询任务
    String assignee = "小王";
    Task task = taskService.createTaskQuery()
        .processDefinitionKey("myEvection")     //流程Key
        .taskAssignee(assignee)                 //只查询当前任务负责人的任务
        .singleResult();
    // 4.完成待办任务,参数:任务id
    taskService.complete(task.getId());
}

执行上述代码之前,act_ru_task表中的内容还是第一步创建出差申请单:
在这里插入图片描述

执行上述代码之前,act_ru_task表中的内容已经替换为了当前流程:
在这里插入图片描述

而之前的流程就放到了act_hi_taskinst历史的任务实例当中去了:
在这里插入图片描述

5.6 流程定义信息查询

查询流程相关信息也是经常要用到的操作,通常包含对流程定义,流程部署,流程定义版本的查询。

/**
  * 查询流程定义
  */
@Test
public void findProcessDefinitionTest(){
    // 1.创建流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2.获取repositoryService资源管理实例
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 3.通过repositoryService获取ProcessDefinitionQuery对象
    ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
    // 4.查询出当前所有的流程定义
    List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("myEvection")  // 根据流程key(id)进行查询
        .orderByProcessDefinitionVersion()                 // 按照版本排序
        .desc()                                            // 倒序
        .list();
    // 5.输出流程定义信息
    definitionList.forEach(processDefinition -> {
        System.out.printf("----------------------------------------");
        System.out.println("流程定义 id="+processDefinition.getId());
        System.out.println("流程定义 name="+processDefinition.getName());
        System.out.println("流程定义 key="+processDefinition.getKey());
        System.out.println("流程定义 Version="+processDefinition.getVersion());
        System.out.println("流程部署ID ="+processDefinition.getDeploymentId());
    });
}

5.7 流程删除

如果某个流程不想要了,可以选择删除该流程。

/**
  * 流程删除(它影响的表和流程定义时的表)
  */
@Test
public void deleteDeploymentTest() {
    // 1.创建流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2.通过流程引擎获取repositoryService
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 3.删除流程定义,如果该流程定义已有流程实例启动,那么删除时就会报错
    String deploymentId = "1";       // 流程部署id
    repositoryService.deleteDeployment(deploymentId);
    // 4.设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除
    //   设置为false非级别删除方式,如果该流程定义已有流程实例启动,那么删除时就会报错
    //repositoryService.deleteDeployment(deploymentId, true);
}

注意:

  • 使用repositoryService删除流程定义,历史表信息不会被删除

  • 如果该流程定义下没有正在运行的流程,则可以用普通删除

  • 项目开发中级联删除操作一般只开放给超级管理员使用.

5.8 流程资源下载

虽然jdbc也可以把blob类型的数据读取出来,但是这里主要还是用Activiti提供的API来进行操作。

1)引入commons-io的Maven依赖

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

2)代码示例

/**
  * 下载资源文件 
  * @throws IOException
  */
@Test
public void  findBpmnFileTest() throws IOException {
    // 1.创建流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2.通过流程引擎获取repositoryService
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 3、得到流程定义查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
        .processDefinitionKey("myEvection")
        .singleResult();
    // 4、通过流程定义信息,得到部署ID
    String deploymentId = processDefinition.getDeploymentId();
    // 5、通过repositoryService的方法,实现读取图片信息和bpmn信息
    //  5.1 获取png图片的流
    InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
    //  5.2 获取bpmn文件的流
    InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());
    //  6、构造OutputStream流
    File file_png = new File("d:/first.png");
    File file_bpmn = new File("d:/first.bpmn");
    FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
    FileOutputStream pngOut = new FileOutputStream(file_png);
    //  7、输入流,输出流的转换
    IOUtils.copy(pngInput, pngOut);
    IOUtils.copy(bpmnInput, bpmnOut);
    //  8、关闭相关流
    pngOut.close();
    bpmnOut.close();
    pngInput.close();
    bpmnInput.close();
}

这只是在本地是这么操作的,是比较原生的写法,更有利于理解。

如果是在web项目中,就直接按文件下载的方式传输数据就可以了。

5.9 流程历史信息的查看

/**
  * 查看历史信息
  */
@Test
public void findHistoryInfoTest(){
    // 1.创建流程引擎
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2.获取HistoryService
    HistoryService historyService = processEngine.getHistoryService();
    // 3.获取 actinst表的查询对象
    HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
        // 查询 actinst表,条件:根据 InstanceId 查询(等价于: instanceQuery.processInstanceId("2501");  根据 InstanceId 查询)
    instanceQuery.processDefinitionId("myEvection:1:4");
    // 增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序
    instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
    // 查询所有内容
    List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
    // 输出查询结果
    activityInstanceList.forEach(hi -> {
        System.out.println("<==========================>");
        System.out.println(hi.getActivityId());
        System.out.println(hi.getActivityName());
        System.out.println(hi.getProcessDefinitionId());
        System.out.println(hi.getProcessInstanceId());
    });
}

5.10 流程实例的挂起

在一些情况下可能由于流程变更需要将当前运行的流程暂停(挂起)而不是直接删除,流程暂停后将不会继续执行。

比如每月的最后一天不处理出差申请呀,财务审批流程改变需要暂停已经发起的审批等等。

流程实例的挂起也有下面两种方式:

1)将单个流程实例的挂起和激活

/**
  * 挂起、激活单个流程实例
  */
@Test
public void suspendSingleProcessInstance(){
    // 1. 创建ProcessEngine流程引擎对象
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2、获取RuntimeService
    RuntimeService runtimeService = processEngine.getRuntimeService();
    // 3、通过RuntimeService获取流程实例对象
    ProcessInstance instance = runtimeService.createProcessInstanceQuery()
        .processInstanceId("27501")
        .singleResult();
    // 4、得到当前流程实例的暂停状态,true-已暂停  false -激活
    boolean suspended = instance.isSuspended();
    // 5、获取流程实例id
    String instanceId = instance.getId();
    // 6、判断是否已经暂停,如果已经暂停,就执行激活操作
    if(suspended){
        // 如果已经暂停,就执行激活
        runtimeService.activateProcessInstanceById(instanceId);
        System.out.println("流程实例id:"+instanceId+"已经激活");
    }else {
        // 7、如果是激活状态,就执行暂停操作
        runtimeService.suspendProcessInstanceById(instanceId);
        System.out.println("流程实例id:"+instanceId+"已经暂停");
    }
}

2)将全部流程实例的挂起和激活

/**
  * 全部流程实例的挂起和激活
  * suspend 暂停
  */
@Test
public void suspendAllProcessInstance(){
    // 1. 创建ProcessEngine流程引擎对象
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    // 2、获取Repositoryservice
    RepositoryService repositoryService = processEngine.getRepositoryService();
    // 3、根据流程定义Key查询流程定义,获取流程定义的查询对象
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                                                           .processDefinitionKey("myEvection")
                                                           .singleResult();
    // 4、获取当前流程定义的实例是否都是挂起状态
    boolean suspended = processDefinition.isSuspended();
    // 5、获取流程定义的id
    String definitionId = processDefinition.getId();
    // 6、如果是挂起状态,改为激活状态
    if(suspended){
        // 如果是挂起,可以执行激活的操作,参数1:流程定义id 参数2:是否激活,参数3:激活时间
        repositoryService.activateProcessDefinitionById(definitionId, true, null);
        System.out.println("流程定义id:"+definitionId+",已经被激活");
    }else {
        // 7、如果是激活状态,改为挂起状态,参数1:流程定义id 参数2:是否暂停 参数3 :暂停的时间
        repositoryService.suspendProcessDefinitionById(definitionId, true, null);
        System.out.println("流程定义id:"+definitionId+",已经被挂起");
    }
}

这两者的区别也就是一个是查询实例,拎一个查询的是流程定义罢了

六、小结

上面已经演示了常见的BPMN操作和流程操作,更偏向于新手理解相关API

但是在绘制流程图的时候,暂时都是把责任人等信息写死了。这显然在实际的业务中是难以适应业务的变化的。

并且流程审批的时候,下一个审批人根本不知道审批的具体内容是啥。

比如上面的出差申请,具体要出差去哪,出差几天,都是不知道的。

因为这些数据在业务系统当中,而不是在Activiti中。

只有两者联动起来才能完成实际的业务开发需求,这个是需要注意的。

下一篇博客会讲诉Activiti的中流程实例、用户任务、流程变量以及网关的使用,更加贴合实际开发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/490610.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

4D成像雷达风口,谁在快速崛起?

4D成像雷达正进入规模量产落地的关键窗口期。 高工智能汽车注意到&#xff0c;毫米波雷达的发展某种程度上可以分为两个阶段&#xff1a;第一个阶段&#xff0c;传统毫米波雷达时代&#xff0c;市场基本被博世、大陆、安波福等国际Tier1巨头把持&#xff0c;市场格局长期稳固&…

树形结构的三级分类如何实现?

概述&#xff1a; 本三级联动分类服务端使用的是: Springboot MyBatis-plus&#xff0c;前端使用的是&#xff1a;VueElementUI&#xff0c;树形控件使用的是el-tree。本三级联动分类可以把任一拖拽子项到其它目录&#xff0c;可以添加、编辑、删除分类。 效果图&#xff1a…

编译原理笔记(一)引论

文章目录 1.什么是编译程序2.编译过程和编译程序的结构2.1.编译过程概述2.2.编译程序的结构2.3.编译阶段的组合 3.解释程序和一些软件工具3.1.解释程序3.2.处理源程序的软件工具 4.PL/0语言编译系统 学习总结&#xff1a;这一部分是编译原理的绪论部分内容&#xff0c;对编译程…

Tokenizer分词

分词的一般流程 在使用神经网络处理自然语言处理任务时&#xff0c;我们首先需要对数据进行预处理&#xff0c;将数据从字符串转换为神经网络可以接受的格式&#xff0c;一般会分为如下几步&#xff1a; &#xff08;1&#xff09;分词&#xff1a;使用分词器对文本数据进行分…

STM32CUBEMX 待机模式最简单的RTC定时唤醒(低功耗电池产品必备)

文章意义&#xff1a; 看到很多技术帖子讲述RTC定时唤醒功能的时候&#xff0c;老是需要去读取当前时间&#xff0c;再设定下一个闹钟唤醒时间&#xff0c;无形中多了很多变量和操作。所以我决定分享一种简单的RTC定时唤醒方法&#xff0c;适合于不需要实现具体时间获取的场合…

企业遇到知识管理困境该怎么办?这里有解决方案!寻找Baklib

随着企业业务不断扩大&#xff0c;员工数量的增加&#xff0c;知识管理成为了企业面临的一个重要问题。企业需要管理大量的知识&#xff0c;如产品手册、流程规范、客户信息等&#xff0c;这些知识对企业的生产和经营至关重要。但是&#xff0c;如何高效地管理这些知识&#xf…

LeetCode_双指针_中等_24.两两交换链表中的节点

目录 1.题目2.思路3.代码实现&#xff08;Java&#xff09; 1.题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&a…

第40讲:Python for-in循环语句使用索引遍历序列

文章目录 方法一&#xff1a;遍历的是序列的元素方法二&#xff1a;遍历的是序列的索引方法三&#xff1a;while循环遍历实现方法四&#xff1a;调用内置函数enumerate实现1.什么是enumerate函数2.调用内置函数enumerate实现索引遍历序列 如果在遍历序列的过程中&#xff0c;需…

国产高端GPU,国产替代加速(附国产厂家汇总)

前言 2022年8月9日&#xff0c;壁仞科技在上海发布首款通用GPU芯片BR100&#xff0c;标志着中国企业第一次打破了此前一直由国际巨头保持的通用GPU全球算力纪录&#xff1b; 8月31日&#xff0c;美国政府命令芯片厂商英伟达&#xff08;NVIDIA&#xff09;以及超威半导体&…

借助 Google Play 游戏电脑版 Com2uS 为用户打造多平台无缝体验

作者 / Google Play 游戏总监 Arjun Dayal 吸引潜在用户在 PC 端畅享游戏 《魔灵召唤&#xff1a;克罗尼柯战记》是韩国游戏开发商 Com2uS 于 2023 年 3 月面向全球发布的一款移动端大型多人在线角色扮演游戏。迄今为止&#xff0c;《魔灵召唤》在全球的下载量超过 1.8 亿&…

Aztec:混合zkRollup,而非zkEVM

1. 引言 Aztec zkRollup为混合zkRollup&#xff1a; 支持通用私有计算的加密zkRollup&#xff08;命名为Aztec&#xff09;&#xff1a;构建trustless、可扩展的、去中心化的Layer2 zkRollup&#xff0c;同时支持private smart contract execution。同时支持public state和pr…

C++ Primer阅读笔记--参数传递

目录 1--三种基本传递方式 2--数组形参 3--main函数传递参数 4--传递可变形参 1--三种基本传递方式 ① 值传递&#xff1a; 使用值传递时&#xff0c;初始值会拷贝给变量&#xff0c;对变量的改动不会改变初始值的值&#xff1b; ② 指针传递&#xff1a; 使用指针传递时&…

Mysql 查询性能优化

查看数据库用户连接数量 show processlist;分析表结构 索引 show index from conference;查询锁状态 show status like %lock%;是否开启慢查询 show variables like %slow_query_log%;日志查询默认情况下&#xff1a;slow_query_log的Value为OFF 如要开启慢查询日志&#…

2023最新软件测试面试题汇总

常见的面试题汇总 1、你做了几年的测试、自动化测试&#xff0c;说一下 selenium 的原理是什么&#xff1f; 我做了五年的测试&#xff0c;1年的自动化测试&#xff1b; selenium 它是用 http 协议来连接 webdriver &#xff0c;客户端可以使用 Java 或者 Python 各种编程语言…

AI奇点将至 如何成为人工智能驱动型公司

‍数据智能产业创新服务媒体 ——聚焦数智 改变商业 2023年4月16日&#xff0c;中泰证券首席经济学家李迅雷先生发表了《奇点将至&#xff1a;AI或开启新一轮科技革命》的文章。李迅雷先生认为&#xff0c;以智能化为特征的第四次工业革命轮廓日渐清晰&#xff0c;在世界百年未…

Linux网络编程:socket、客户端服务器端使用socket通信

socket socket&#xff08;套接字&#xff09;&#xff0c;用于网络中不同主机间进程的通信。 socket是一个伪文件&#xff0c;包含读缓冲区、写缓冲区。 socket必须成对出现。 socket可以建立主机进程间的通信&#xff0c;但需要协议&#xff08;IPV4、IPV6等&#xff09;…

[230507]托福听力真题TPO66词汇 |无重复|20:50~21:55 + 8:00~8:30

目录 conversation 1 conversation 2 ​ TPO66 Lecture ppt词汇 TPO66 Lecture 笔记词汇 conversation 1 conference / ˈkɑːnfərəns /n 会议terrific / təˈrɪfɪk /adj 极好的presentation / ˌpriːz(ə)nˈteɪʃ…

发送Ajax get请求详解

发送AJAX get请求&#xff0c;前端代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>ajax get请求</title> </head> <body> <script type"text/java…

第三十一章 Unity骨骼动画

关于骨骼动画的原理&#xff0c;我们这里不再详细介绍&#xff0c;有不清楚的可以回去看DirectX课程和3dsMAX课程。接下来&#xff0c;我们来讲解一下Unity的骨骼动画系统。Unity 的动画系统基于动画剪辑&#xff08;Animation Clip&#xff09;的概念&#xff0c;它的本质就是…

Linux 安装时,各个分区的作用是什么?

在这里&#xff0c;我说说一开始Linux为什么需要分区。 因为 Linux 是一个多用户操作系统。 多用户意味着一个问题&#xff1a;并非所有用户的操作都是可控的。 而系统正常运行的话&#xff0c;必须要一定的剩余空间。 这也就意味着&#xff1a;如果一个用户自己把空间占满…