Flowable工作流——基础篇

news2024/11/29 2:45:09

1. 介绍

Flowable是BPMN的一个基于Java的软件实现,但是不仅仅限于BPMN,还有DMN决策表和CMMN Case管理引擎,并且有自己的用户管理,微服务API的功能,是一个服务平台。
是由开发了Acitivity6的开发人员,再次升级开发的。

2. 项目搭建

2.1 初始化

  • 构建一个普通maven项目。
  • 引入依赖:
    <dependencies>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-engine</artifactId>
            <version>6.3.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.21</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.7</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.1.7</version>
        </dependency>
    </dependencies>
  • 新建测试类。
 @Test
    public void testProcessEngine(){
        // 流程配置对象
        ProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration();

        // 数据库配置
        configuration.setJdbcDriver("com.mysql.jdbc.Driver");
        configuration.setJdbcUsername("root");
        configuration.setJdbcPassword("root");
        configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8");
        // 配置如果表结构不存在就新建
        configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);


        // 构造核心流程对象
        ProcessEngine processEngine = configuration.buildProcessEngine();
        System.err.println(processEngine);
    }
  • 耐心等待运行(创建表结构)
    在这里插入图片描述
  • 配置slf4j,在resource下新建配置文件log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/logFile.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
  • 配置logback,resource下新建logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <property name="APP_NAME" value="MY_APP_NAME" />
    <property name="LOG_DIR" value="logs" />
    <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS}  %-5level [%thread] %logger{15} - %msg%n" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %boldYellow([%thread])  %cyan(%logger{15}) %msg%n"/>

    <contextName>${APP_NAME}</contextName>

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>${LOG_DIR}/logFile.log</file>
        <append>true</append>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_DIR}/dayLogFile.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <!-- 使用root的appender-ref -->
    <logger name="com.example.Logger1" level="DEBUG" additivity="true">
    </logger>

    <!-- 不使用root的appender-ref -->
    <logger name="com.example.Logger2" level="DEBUG" additivity="false">
    </logger>

    <logger name="com.example.Logger3" level="DEBUG" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>

    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
        <appender-ref ref="RollingFile" />
    </root>
</configuration>
  • 再次启动测试,可以看到是彩色的日志
    在这里插入图片描述

3. 部署流程测试

使用官方给的请假测试流程。

3.1 流程图

  • 流程图如下:
    在这里插入图片描述

    1. 发起请求之后由管理员去审批:通过或者拒绝
    2. 通过/拒绝,之后触发不同的流程。
  • 流程图说明

    1. 左侧的圆圈叫做启动事件(start event)。这是一个流程实例的起点。
    2. 第一个矩形是一个用户任务(user task)。这是流程中用户操作的步骤。在这个例子中,管理员需要批准或驳回申请。
    3. 取决于管理员的决定,排他网关(exclusive gateway) (带叉的菱形)会将流程实例路由至批准或驳回路径。
    4. 如果批准,则需要将申请注册至某个外部系统,并跟着另一个用户任务,将经理的决定通知给申请人。当然也可以改为发送邮件。
    5. 如果驳回,则为雇员发送一封邮件通知他。

3.2 流程文件

  • 对应的xml文件:将xml放到resource文件夹下,并命名为holiday-request.bpmn20.xml
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             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:flowable="http://flowable.org/bpmn"
             typeLanguage="http://www.w3.org/2001/XMLSchema"
             expressionLanguage="http://www.w3.org/1999/XPath"
             targetNamespace="http://www.flowable.org/processdef">

    <process id="holidayRequest" name="Holiday Request" isExecutable="true">

<!--        开始-->
        <startEvent id="startEvent"/>
<!--        来源:startEvent 目的地:approveTask-->
        <sequenceFlow sourceRef="startEvent" targetRef="approveTask"/>

<!--        用户任务-->
        <userTask id="approveTask" name="Approve or reject request"/>
<!--        用户任务目的地排他网关-->
        <sequenceFlow sourceRef="approveTask" targetRef="decision"/>


<!--        排他网关-->
        <exclusiveGateway id="decision"/>
<!--        排他网关目标1-->
        <sequenceFlow sourceRef="decision" targetRef="externalSystemCall">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[
          ${approved}
        ]]>
            </conditionExpression>
        </sequenceFlow>

<!--        排他网关目标2-->
        <sequenceFlow  sourceRef="decision" targetRef="sendRejectionMail">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[
          ${!approved}
        ]]>
            </conditionExpression>
        </sequenceFlow>

<!--        同意流程节点-->
        <serviceTask id="externalSystemCall" name="Enter holidays in external system"
                     flowable:class="org.flowable.CallExternalSystemDelegate"/>
        <sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>

<!--        同意之后的节点-->
        <userTask id="holidayApprovedTask" name="Holiday approved"/>
<!--        通过-指向结束-->
        <sequenceFlow sourceRef="holidayApprovedTask" targetRef="approveEnd"/>

<!--        拒绝流程让任务节点-->
        <serviceTask id="sendRejectionMail" name="Send out rejection email"
                     flowable:class="org.flowable.SendRejectionMail"/>
<!--        拒绝-指向结束-->
        <sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>

        <endEvent id="approveEnd"/>

        <endEvent id="rejectEnd"/>
    </process>

</definitions>

3.3 部署文件

  • 新建单元测试文件
public class DoFlowable {

    ProcessEngineConfiguration configuration = null;

    /**
     * 获取flowable流引擎对象
     */
    @Before
    public void testProcessEngine(){
        // 流程配置对象
        configuration = new StandaloneProcessEngineConfiguration();
        // 数据库配置
        configuration.setJdbcDriver("com.mysql.jdbc.Driver");
        configuration.setJdbcUsername("root");
        configuration.setJdbcPassword("root");
        configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8");
        // 配置如果表结构不存在就新建
        configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
    }

    /**
     * 部署流程
     */
    @Test
    public void testDeploy(){
        // 获取 processEngine 对象
        ProcessEngine processEngine = configuration.buildProcessEngine();

        // 获取 repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 获取 deployment 对象
        Deployment deployment = repositoryService.createDeployment()// 创建Deployment对象
                .addClasspathResource("holiday-request.bpmn20.xml") // 添加流程部署文件
                .name("请求流程") // 设置部署流程的名称
                .deploy(); // 执行

        System.err.println("deployment.getId() = " + deployment.getId());
        System.out.println("deployment.getName() = " + deployment.getName());
    }

}
  • 执行之后:
    在这里插入图片描述
  • 查看数据库:可以看到数据
    在这里插入图片描述

4. 流程API

  • 先封装一个工具类,方便用来获取ProcessEngine对象
public class ProcessEngineUtils {

    /**
     * 获取flowable流引擎对象
     */
    public static ProcessEngine getProcessEngine(){
        // 流程配置对象
        ProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration();
        // 数据库配置
        configuration.setJdbcDriver("com.mysql.jdbc.Driver");
        configuration.setJdbcUsername("root");
        configuration.setJdbcPassword("root");
        configuration.setJdbcUrl("jdbc:mysql://localhost:3306/flowable-learn?serverTimezone=UTC&nullCatalogMeansCurrent=true&useSSL=true");
        // 配置如果表结构不存在就新建
        configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

        // 构造核心流程对象
        return configuration.buildProcessEngine();
    }
}

4.1 查询操作

    /**
     * 查询流程定义信息
     */
    @Test
    public void deploymentQuery(){
        ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 获取查询对象
        ProcessDefinitionQuery processQuery = repositoryService.createProcessDefinitionQuery();
        // 定义查询信息(单个查询)
        ProcessDefinition definition = processQuery.deploymentId("2501").singleResult();
    }

4.2 删除操作

    /**
     * 删除流程定义
     */
    @Test
    public void deployDel(){
        ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        repositoryService.deleteDeployment("1"); // 删除对应id的流程,启动中不可以删除
//        repositoryService.deleteDeployment("1", true); // 删除对应id的流程(包含其中的过程数据),不考虑启动状态。
    }

4.3 启动流程

    /**
     * 启动流程
     */
    @Test
    public void deployRun(){
        // 配置传递的参数
        Map<String, Object> params = new HashMap<>();
        params.put("employee","王五");
        params.put("days",3);
        params.put("description","累了");

        ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 1:这里的 key 对应配置文件中的 process 的 id
        // 2:传递的参数
        ProcessInstance holidayRequest = runtimeService.startProcessInstanceByKey("holidayRequest", params);
    }
  • 查看传入的数据
    在这里插入图片描述

  • 查看启动的流程
    在这里插入图片描述

  • 查看执行进度
    在这里插入图片描述

4.4 管理员查询

  • 修改xml中的审批处理人
<!--        用户任务-->
        <userTask id="approveTask" name="Approve or reject request" flowable:assignee="Ekko"/>
<!--        用户任务目的地排他网关-->
        <sequenceFlow sourceRef="approveTask" targetRef="decision"/>
  • 使用删除api,第二个参数传入true,级联删除任务数据。
  • 重新部署流程。
  • 再次重新启动流程。可以看到我们指定的审批人为:Ekko。
    在这里插入图片描述
  • 查询代码
    /**
     * 任务查询
     */
    @Test
    public void taskQuery(){
        ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey("holidayRequest") // 指定流程key
                .taskAssignee("Ekko") // 指定处理人
                .list();
        for (Task task : list) {
            System.out.println(task.getProcessDefinitionId());
            System.out.println(task.getName());
            System.out.println(task.getAssignee());
            System.out.println(task.getDescription());
            System.out.println(task.getId());
        }
    }

4.5 管理员审批

  • 修改配置文件中排他网关的两种处理走的类这里的配置修改之后需要重新部署一下流程。
<!--        同意流程节点-->
        <serviceTask id="externalSystemCall" name="Enter holidays in external system"
                     flowable:class="com.yy.flowable.service.AppService"/>
        <sequenceFlow sourceRef="externalSystemCall" targetRef="holidayApprovedTask"/>
<!--        拒绝流程让任务节点-->
        <serviceTask id="sendRejectionMail" name="Send out rejection email"
                     flowable:class="com.yy.flowable.service.RejectService"/>
<!--        拒绝-指向结束-->
        <sequenceFlow sourceRef="sendRejectionMail" targetRef="rejectEnd"/>
  • 新增流程处理类
    在这里插入图片描述
  • 请假通过接口
/**
 * @author : JinMing Zhou
 * @description: 通过类
 * @date : 2023/1/9 17:48
 */
public class AppService implements JavaDelegate {

    /**
     * 触发器,流程走到这里执行该方法
     * @param delegateExecution
     */
    @Override
    public void execute(DelegateExecution delegateExecution) {
        // 通过,执行逻辑
        System.out.println("通过。");
    }
}
  • 请假拒绝接口
/**
 * @author : JinMing Zhou
 * @description: 拒绝类
 * @date : 2023/1/9 17:48
 */
public class RejectService implements JavaDelegate {

    /**
     * 请假流程拒绝触发器
     * @param delegateExecution
     */
    @Override
    public void execute(DelegateExecution delegateExecution) {
        System.err.println("不给通过!");
    }
}

  • 处理操作
    /**
     * 处理流程
     */
    @Test
    public void completeTask(){
        // 指定审批参数
        Map<String, Object> params = new HashMap<>();
        params.put("approved",false);

        ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        // 查询任务

        Task task = taskService.createTaskQuery()
                .processDefinitionKey("holidayRequest") // 指定流程key
                .taskAssignee("Ekko") // 指定处理人
                .singleResult();
        // 处理操作
        taskService.complete(task.getId(), params);
    }

在这里插入图片描述

4.6 历史记录查询

    /**
     * 历史信息查询
     */
    @Test
    public void historyQuery(){
        ProcessEngine processEngine = ProcessEngineUtils.getProcessEngine();
        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processDefinitionId("holidayRequest:1:17503")
                .finished()
                .orderByHistoricActivityInstanceEndTime().asc()
                .list();
        for (HistoricActivityInstance historicActivityInstance : list) {
            System.err.println(historicActivityInstance.getActivityId() + " took "
                    + historicActivityInstance.getDurationInMillis() + " milliseconds");
        }
    }

在这里插入图片描述

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

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

相关文章

nacos的使用

此篇博客是对nacos安装运行进行简单的介绍&#xff0c;后续博客会介绍下nacos的简单使用。nacos的安装安装可以去github上进行下载&#xff0c;下载地址&#xff08;不建议下载最新版本&#xff0c;可以找比较稳定的版本&#xff09;可以点解Tags查看所有历史版本我下载的是2.2…

基于 js 制作一个贪吃蛇小游戏

目录前言&#xff1a;项目效果展示&#xff1a;代码实现思路&#xff1a;使用方法&#xff1a;实现代码&#xff1a;总结&#xff1a;前言&#xff1a; 在工作学习之余玩一会游戏既能带来快乐&#xff0c;还能缓解生活压力&#xff0c;跟随此文一起制作一个小游戏吧。 描述&…

ESXI8.0一键安装黑群晖DSM7

&#x1f388; 作者&#xff1a;互联网-小啊宇 &#x1f388; 简介&#xff1a; CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作&#xff0c;擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…

如何做好项目管理

项目管理概述 什么是项目 项目 是为创造独特的产品、服务或者成果而进行的临时性工作 项目三要素&#xff1a;临时性、独特性、渐进明确性 什么是项目管理 项目管理通过合理运营和整合项目相关活动&#xff0c;以满足项目目标达成的过程 项目与日常工作的区别 项目&…

设计测试用例

⭐️前言⭐️ 这篇文章主要介绍测试用例相关的知识&#xff0c;一个优秀的测试人员&#xff0c;需要具备设计优秀测试用例的能力。 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主将持续更新学习记录收获&…

基于启发式蝙蝠算法、粒子群算法、花轮询算法和布谷鸟搜索算法的换热器PI控制器优化(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 本文采用蝙蝠算法、粒子群优化、花轮询算法和布谷鸟搜索算法&#xff0c;对管壳式换热器的控制系统进行了建模和计算机仿真。为…

trie树入门

trie树分为普通的trie树和01trie树两者可以实现成树&#xff0c;很大一部分原因是&#xff1a;只有26个字母和01两种状态&#xff0c;一个结点度数不会太大&#xff0c;而且字符串长度和位数不会很大&#xff0c;更容易存储普通trie树维护了一堆字符串集合的前缀&#xff0c;in…

Elastic-Job分布式任务调度(4):Elastic-Job高级

1 事件追踪 Elastic-Job-Lite在配置中提供了JobEventConfiguration&#xff0c;支持数据库方式配置&#xff0c;会在数据库中自动创建JOB_EXECUTION_LOG和JOB_STATUS_TRACE_LOG两张表以及若干索引&#xff0c;来记录作业的相关信息。 1.1 修改Elastic-Job配置类 在ElasticJo…

电商人必读:2022中国电商市场发展洞察报告(人群、品类、品牌、玩法).pdf(附下载链接)...

省时查报告-专业、及时、全面的行研报告库省时查方案-专业、及时、全面的营销策划方案库【免费下载】2022年12月份热门报告盘点罗振宇2023年跨年演讲PPT原稿吴晓波2022年年终秀演讲PPT原稿《底层逻辑》高清配图华为2021数字化转型&#xff1a;从战略到执行.pdf华为项目管理金种…

如何理解操作系统

路灯很多&#xff0c;希望你找到自己的月亮。 作者&#xff1a;阿润菜菜 目录 操作系统是什么 为什么设计操作系统 理解操作系统的作用 如何理解操作系统对软硬件管理&#xff1f; 操作系统为什么要对软硬件资源进行管理呢&#xff1f; 什么是系统调用和库函数 总结 操…

【docker13】Redis面试题

面试题 问题&#xff1a; 1~2亿条数据需要缓存&#xff0c;请问如何设计这个存储案例&#xff1f; 回答&#xff1a; 单机单台不可能的&#xff0c;肯定是分布式存储&#xff08;那如何用redis实现呢&#xff1f;) 解决1&#xff1a; 哈希取余分区 优点&#xff1a; 简单粗暴…

项目管理系统的类型

“系统”一词有两个不同的定义&#xff1a;一、定义某事如何完成的原则和程序&#xff0c;二、复杂整体的部分。因此&#xff0c;根据所使用的定义&#xff0c;项目管理系统也可以有两种不同的含义。 第一个是指定义如何执行项目的完整过程和原则系统。此定义包括所有项目管理以…

windows10上安装Python3.11.1

1&#xff09;下载Python3.11.1 Python官网下载地址&#xff1a;https://www.python.org/ package意思是下载压缩安装包&#xff0c;installer是.exe的安装程序。 根据自己电脑需求选择&#xff0c;这里我选择的是64位 2&#xff09;安装 双击安装包&#xff0c;进行安装。…

VScode编译调试C++环境

首先去官网下载vscodehttps://code.visualstudio.com/ 为了编译C/C&#xff0c;要使用gcc&#xff0c;Windows本身不支持gcc&#xff0c;所以有了MinGW&#xff0c;我用的是dev带的MinGW&#xff0c;也可以自己安装MinGW&#xff0c;或者用VS的编译器&#xff08;MinGW gcc下载…

喜报!COSCon'22中国开源年会获评 2022 中国最受开发者欢迎的技术活动

2023 年 1 月 5 日&#xff0c;中国技术先锋年度评选2022 中国最受开发者欢迎的技术活动榜单正式发布。作为中国领先的新一代开发者社区&#xff0c;SegmentFault 思否依托社区活动板块&#xff08;https://segmentfault.com/events&#xff09;及全站数百万开发者用户行为数据…

浏览器怎么录制网页视频?3种网页视频录制方法

我们每天都会在浏览器上观看大量的视频&#xff0c;尤其是在爱奇艺、腾讯、哔哩哔哩等网页上。有时候就会观看到一些精彩的视频画面&#xff0c;就想要将这些画面给下载。那怎么把网页视频录制下来&#xff1f;今天本文就给大家分享3种有效的网页视频录制方法&#xff0c;有需要…

Linux 环境使用定时任务执行shell脚本

前言&#xff1a;Linux添加定时任务需要依赖crond服务&#xff0c;如果没有该服务&#xff0c;需要先安装&#xff1a;yum -y install crontabs 1、crond服务相关命令介绍 启动crond服务&#xff1a;service crond start 停止crond服务&#xff1a;service crond stop 重启cro…

【NI Multisim 14.0原理图设计基础——放置元器件】

目录 序言 &#x1f349; 一、放置元器件 序言 NI Multisim最突出的特点之一就是用户界面友好。它可以使电路设计者方便、快捷地使用虚拟元器件和仪器、仪表进行电路设计和仿真。 首先启动NI Multisim 14.0&#xff0c;打开如图所示的启动界面&#xff0c;完成初始化后&…

第一行代码Androiod第三版 笔记 第九章丰富你的程序,运用手机多媒体

文章目录前言一、通知渠道是什么&#xff1f;二、快速入门1. 书写通知2.通知有了 &#xff0c;点击也没动静啊- PendingIntent3 点击完之后&#xff0c;通知不消失怎么办4 通过setStyle() 来是实现长文字通知5 还想放张图6 不同通知之间也有等级差异三、 使用相机7 调用相机8 从…

Linux工具学习之【gcc/g++】

✨个人主页&#xff1a; Yohifo &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f38a;每篇一句&#xff1a; 图片来源 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 Whatever is worth doing is worth doing well. 任何值得去做的事情&#xff0…