Angular面试题汇总系列一

1. 如何理解Angular Signal

Angular Signals is a system that granularly tracks how and where your state is used throughout an application, allowing the framework to optimize rendering updates.

什么是信号

信号是一个值的包装器,可以在该值发生变化时通知感兴趣的消费者。信号可以包含任何值,从简单的原语到复杂的数据结构。

信号的值总会通过 getter 函数读取,这使得 Angular 可以跟踪信号的使用位置。

信号可以是可写的或只读的。

可写信号

可写信号提供了一个 API 来直接更新它们的值。你可以通过使用信号的初始值调用 signal 函数来创建可写信号:

const count = signal(0);
// Signals are getter functions - calling them reads their value.
console.log('The count is: ' + count());

要更改可写信号的值,你可以直接 .set():

count.set(3);

或者使用 .update() 操作从前一个值计算出一个新值:

// Increment the count by 1.
count.update(value => value + 1);

在处理包含对象的信号时,有时直接改变该对象很有用。例如,如果对象是一个数组,你可能希望在不完全替换数组的情况下推送一个新值。要进行这样的内部更改,请使用 .mutate 方法:

const todos = signal([{title: 'Learn signals', done: false}]);

todos.mutate(value => {
  // Change the first TODO in the array to 'done: true' without replacing it.
  value[0].done = true;
});

计算信号

计算信号是从其他信号中派生出来的。可以使用 computed 并指定推导函数来定义一个:

const count: WritableSignal<number> = signal(0);
const doubleCount: Signal<number> = computed(() => count() * 2);

doubleCount 信号取决于 count。每当 count 更新时,Angular 知道任何依赖于 count 或 doubleCount 东西也需要更新。

计算信号都是惰性计算和记忆的

在第一次读取 doubleCount 之前,不会运行 doubleCount 的派生函数以计算其值。一旦计算出来,这个值就会被缓存起来,以后读取 doubleCount 将返回缓存的值而不用重新计算。

当 count 发生变化时,它会告诉 doubleCount 它的缓存值不再有效,并且该值只会在下一次读取 doubleCount 时重新计算。

因此,在计算信号中执行计算量大的推导(例如过滤数组)是相当安全的。

计算信号不是可写信号
你不能直接为计算信号赋值。比如,

doubleCount.set(3);

会产生编译错误,因为 doubleCount 不是 WritableSignal。

计算信号的依赖性是动态的

只能跟踪推导期间实际读取过的信号。例如,在此计算中,只会有条件地读取 count 信号:

const showCount = signal(false);
const count = signal(0);
const conditionalCount = computed(() => {
  if (showCount()) {
    return `The count is ${count()}.`;
  } else {
    return 'Nothing to see here!';
  }
});

读取 conditionalCount 时,如果 showCount 为 false,则没有读取 count 信号就返回了消息 “Nothing to see here!”。这意味着对 count 的更新不会导致重新计算。

如果稍后将 showCount 设置为 true 并再次读取 conditionalCount,则将重新执行派生并采用 showCount 为 true 的分支,返回显示 count 值的消息。对 count 的更改将使 conditionalCount 的缓存值无效。

请注意,可以删除和添加依赖项。如果 showCount 稍后再次设置为 false,则 count 将不再被视为 conditionalCount 的依赖项。

何时使用副作用

在大多数应用程序代码中很少需要副作用,但在特定情况下可能会有用。下面是一些需要以 effect 作为解决方案的例子:

  • 记录正在显示的数据及其更改时间,用于分析或作为调试工具

  • 在数据与 window.localStorage 之间保持同步

  • 添加无法用模板语法表达的自定义 DOM 行为

  • 对 canvas、图表库或其他第三方 UI 库执行自定义渲染

如何理解 Web Worker

在Angular中,Web Worker是一种运行在浏览器后台线程的JavaScript,它允许你执行任务而不会冻结用户界面。这对于执行密集型计算或长时间运行的任务特别有用,因为这些任务可能会阻塞主线程,导致用户界面变得不响应。
主线程与工作线程:

主线程:负责处理UI交互和DOM操作。
工作线程:运行Web Worker,处理后台任务,不会直接影响UI。
避免UI阻塞:
通过将计算密集型任务放在Web Worker中执行,可以避免主线程阻塞,从而提高应用的响应性和性能。

数据交换:
主线程和工作线程之间通过消息传递进行通信。你可以使用postMessage方法发送消息给Worker,Worker也可以通过postMessage向主线程发送消息。

创建Web Worker:
在Angular中,你可以创建一个服务来管理Web Worker。这个服务负责创建Worker实例,发送消息,并处理从Worker接收到的消息。

Angular服务中的Web Worker:
你可以使用@angular/platform-webworker和@angular/platform-webworker动态模块来创建专门的Worker应用程序或共享Worker。

示例:
以下是一个简单的Angular服务,演示如何使用Web Worker:

// worker.service.ts
import { Injectable } from '@angular/core';
import { Worker } from '@angular/platform-webworker';

@Injectable()
export class WorkerService {
  private worker: Worker;

  constructor() {
    this.worker = new Worker('./worker', { data: 'Hello, worker!' });
    this.worker.onMessage().subscribe(message => {
      console.log('Message from worker:', message);
    });
  }

  sendToWorker(data: any) {
    this.worker.postMessage(data);
  }
}

2 Web Worker 使用场景:

CPU密集型计算:
Web Worker允许在后台线程中运行CPU密集型计算,从而释放主线程以更新用户界面。这对于需要进行大量计算的应用,如生成CAD图纸或进行繁重的几何计算,非常有帮助

离线数据处理和缓存:
通过使用Web Worker和缓存,可以提高应用的性能和响应性。用户可以继续在页面上进行其他操作,而不会受到耗时计算的影响。同时,由于计算结果已经存储在缓存中,当用户需要再次获取时,可以快速地获取到,提高了应用的效率

大量数据计算:
对于需要处理大量数据的Web应用,例如数据分析工具或科学计算应用程序,可以使用Web Worker来处理这些数据。这样可以避免主线程阻塞,提高应用性能

图像处理和媒体编解码:
Web Worker在图像处理和媒体编解码方面也有广泛的应用。例如,可以创建一个Web Worker线程来处理图像调整大小、旋转、裁剪、滤镜等操作,而不阻塞主线程

实时数据推送和通知:
对于需要实时推送数据更新和通知的应用,可以使用Web Worker来处理实时数据的获取和处理任务。这样可以在后台线程中使用WebSocket、Server-Sent Events或定期轮询来获取实时数据,而不会影响主线程的用户交互

轮询服务器状态
有时,浏览器需要轮询服务器状态,以便第一时间得知状态改变。这个工作可以放在Web Worker里面,以避免阻塞主线程

文件数据处理
在某些应用中,可能需要处理大量文件数据,如保存文件数据到服务器。这些操作可以在Web Worker中进行,以避免阻塞用户界面

3. Angular 生命周期Hooks

Angular的生命周期钩子是组件或指令在其生命周期中经历的不同阶段的回调方法。理解这些钩子有助于我们更好地控制组件的行为。以下是Angular组件的生命周期钩子及其用途:

1. ngOnChanges

  • 触发时机: 当输入属性(通过@Input装饰器标记的属性)发生变化时。
  • 用途: 可以用来检测输入属性的变化,并执行相应的逻辑。
  • 操作示例: 重新计算数据、重新渲染视图、更新状态等。

2. ngOnInit

  • 触发时机: 组件或指令被初始化后,且第一次ngOnChanges之后。
  • 用途: 用于执行初始化逻辑,如订阅Observables、获取数据、设置初始状态等。
  • 操作示例: 发起HTTP请求、初始化表单、设置默认值等。

3. ngDoCheck

  • 触发时机: 每次变更检测运行时。
  • 用途: 用于检测Angular自身未检测到的变化,如第三方库的变化。
  • 操作示例: 手动检查变量的变化、执行自定义变更检测逻辑等。

4. ngAfterContentInit

  • 触发时机: 组件内容投影完成后。
  • 用途: 用于在内容投影完成后执行逻辑。
  • 操作示例: 初始化投影内容、设置初始状态等。

5. ngAfterContentChecked

  • 触发时机: 每次变更检测运行后,内容投影检查完成后。
  • 用途: 用于在内容投影检查完成后执行逻辑。
  • 操作示例: 更新投影内容的状态、执行额外的检查等。

6. ngAfterViewInit

  • 触发时机: 组件视图初始化完成后。
  • 用途: 用于在视图初始化完成后执行逻辑。
  • 操作示例: 初始化视图、设置初始状态、操作DOM等。

7. ngAfterViewChecked

  • 触发时机: 每次变更检测运行后,视图检查完成后。
  • 用途: 用于在视图检查完成后执行逻辑。
  • 操作示例: 更新视图的状态、执行额外的检查等。

8. ngOnDestroy

  • 触发时机: 组件或指令被销毁前。
  • 用途: 用于执行清理工作,如取消订阅、清理定时器等。
  • 操作示例: 取消HTTP请求、清理DOM监听器、释放资源等。

示例代码

import { Component, OnInit, OnChanges, DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy, Input } from '@angular/core';

@Component({
  selector: 'app-lifecycle',
  template: `<p>Current value: {{ value }}</p >`
})
export class LifecycleComponent implements OnInit, OnChanges, DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy {
  @Input() value: string;

  constructor() {
    console.log('Constructor called');
  }

  ngOnChanges(changes: SimpleChanges): void {
    console.log('ngOnChanges called', changes);
  }

  ngOnInit(): void {
    console.log('ngOnInit called');
  }

  ngDoCheck(): void {
    console.log('ngDoCheck called');
  }

  ngAfterContentInit(): void {
    console.log('ngAfterContentInit called');
  }

  ngAfterContentChecked(): void {
    console.log('ngAfterContentChecked called');
  }

  ngAfterViewInit(): void {
    console.log('ngAfterViewInit called');
  }

  ngAfterViewChecked(): void {
    console.log('ngAfterViewChecked called');
  }

  ngOnDestroy(): void {
    console.log('ngOnDestroy called');
  }
}

总结

  • ngOnChanges: 输入属性变化时调用。
  • ngOnInit: 初始化完成后调用。
  • ngDoCheck: 每次变更检测时调用。
  • ngAfterContentInit: 内容投影完成后调用。
  • ngAfterContentChecked: 内容投影检查完成后调用。
  • ngAfterViewInit: 视图初始化完成后调用。
  • ngAfterViewChecked: 视图检查完成后调用。
  • ngOnDestroy: 销毁前调用。

4. 如何理解Angular中的依赖注入

依赖注入(DI)是 Angular 中的基本概念之一。DI 被装配进 Angular 框架,并允许带有 Angular 装饰器的类(例如组件、指令、管道和可注入对象)配置它们所需的依赖项。

DI 系统中存在两个主要角色:依赖使用者和依赖提供者。

Angular 使用一种称为 Injector 的抽象来促进依赖消费者和依赖提供者之间的互动。当有人请求依赖项时,注入器会检查其注册表以查看那里是否已有可用的实例。如果没有,就会创建一个新实例并将其存储在注册表中。Angular 会在应用的引导过程中创建一个应用范围的注入器(也称为“根”注入器),并会根据需要创建任何其它注入器。在大多数情况下,你都不需要手动创建注入器,但应该知道有这样一个连接提供者和消费者的层次。

本主题介绍了某个类如何作为依赖项的基本场景。Angular 还允许你使用函数、对象、基本类型(例如字符串或 Boolean)或任何其他类型作为依赖项。

提供依赖项

假设有一个名为 HeroService 的类需要用作组件中的依赖项。

第一步是添加 @Injectable 装饰器以表明此类可以被注入。

@Injectable()
class HeroService {}

下一步是提供它,以便让其在 DI 中可用。可以在多种地方提供依赖项:

在组件级别,使用 @Component 装饰器的 providers 字段。在这种情况下,HeroService 将可用于此组件的所有实例以及它的模板中使用的其他组件和指令。例如:

@Component({
  selector: 'hero-list',
  template: '...',
  providers: [HeroService]
})
class HeroListComponent {}

当你在组件级别注册提供者时,该组件的每个新实例都会获得一个新的服务实例。

在 NgModule 级别,要使用 @NgModule 装饰器的 providers 字段。在这种情况下,HeroService 可用于此 NgModule 或与本模块位于同一个 ModuleInjector 的其它模块中声明的所有组件、指令和管道。当你向特定的 NgModule 注册提供者时,同一个服务实例可用于该 NgModule 中的所有组件、指令和管道。要理解所有边缘情况,参见多级注入器。例如:

@NgModule({
  declarations: [HeroListComponent]
  providers: [HeroService]
})
class HeroListModule {}

在应用程序根级别,允许将其注入应用程序中的其他类。这可以通过将 providedIn: ‘root’ 字段添加到 @Injectable 装饰器来实现:

@Injectable({
  providedIn: 'root'
})
class HeroService {}

当你在根级别提供服务时,Angular 会创建一个 HeroService 的共享实例,并将其注入到任何需要它的类中。在 @Injectable 元数据中注册提供者还允许 Angular 通过从已编译的应用程序中删除没用到的服务来优化应用程序,这个过程称为摇树优化(tree-shaking)。

注入依赖项

注入依赖项的最常见方法是在类的构造函数中声明它。当 Angular 创建组件、指令或管道类的新实例时,它会通过查看构造函数的参数类型来确定该类需要哪些服务或其他依赖项。例如,如果 HeroListComponent 要用 HeroService,则构造函数可以如下所示:

@Component({})
class HeroListComponent {
  constructor(private service: HeroService) {}
}

当 Angular 发现一个组件依赖于一项服务时,它会首先检查注入器中是否已有该服务的任何现有实例。如果所请求的服务实例尚不存在,注入器就会使用注册的提供者创建一个,并在将服务返回给 Angular 之前将其添加到注入器中。

当所有请求的服务都已解析并返回时,Angular 就可以用这些服务实例为参数,调用该组件的构造函数。
在这里插入图片描述
在这里插入图片描述

指定提供者令牌

如果你用服务类作为提供者令牌,则其默认行为是注入器使用 new 运算符实例化该类。

在下面这个例子中,Logger 类提供了 Logger 的实例。

providers: [Logger]

但是,你可以将 DI 配置为使用不同的类或任何其他不同的值来与 Logger 类关联。因此,当注入 Logger 时,会改为使用这个新值。

实际上,类提供者语法是一个简写表达式,可以扩展为由 Provider 接口定义的提供者配置信息。

在这种情况下,Angular 将 providers 值展开为完整的提供者对象,如下所示:

[{ provide: Logger, useClass: Logger }]

展开后的提供者配置是一个具有两个属性的对象字面量:

provide 属性包含一个令牌,该令牌会作为定位依赖值和配置注入器时的键。

第二个属性是一个提供者定义对象,它会告诉注入器如何创建依赖值。提供者定义对象中的键可以是以下值之一:

  • useClass - 此选项告诉 Angular DI 在注入依赖项时要实例化这里提供的类

  • useExisting - 允许你为令牌起一个别名,并引用任意一个现有令牌。

  • useFactory - 允许你定义一个用来构造依赖项的函数。

  • useValue - 提供了一个应该作为依赖项使用的静态值。

5 Angular常见指令有哪些

NgIf:
用于根据条件包含或排除一个元素。

<div *ngIf="condition">Content to show when condition is true.</div>

NgForOf:
用于基于一个数组或可迭代对象来重复元素。

<ul>
  <li *ngFor="let item of items">{{ item }}</li>
</ul>

NgSwitch:
用于在多个条件之间切换显示不同的内容。

<div [ngSwitch]="condition">
  <ng-container *ngSwitchCase="'case1'">Case 1</ng-container>
  <ng-container *ngSwitchDefault>Default case</ng-container>
</div>

NgClass 和 NgStyle:
用于动态添加或移除CSS类和样式。

<div [ngClass]="{'active': isActive, 'disabled': isDisabled}"></div>
<div [ngStyle]="{'color': color, 'font-size': size}"></div>

NgModel:
用于实现双向数据绑定,通常与表单控件一起使用。

<input type="text" [(ngModel)]="name">

FormsModule:
提供了NgModel以及其他表单相关的指令,需要在模块中导入。

import { FormsModule } from '@angular/forms';
@NgModule({
  imports: [FormsModule]
})

NgTemplateOutlet:
用于插入一个模板到指定的位置。

<ng-template let-item="item">
  <div>{{ item }}</div>
</ng-template>
<ng-container *ngTemplateOutlet="template; context: { $implicit: context }"></ng-container>

NgComponentOutlet:
用于动态创建组件实例。

<ng-component-outlet [component]="dynamicComponent"></ng-component-outlet>

NgIfElse:
与NgIf一起使用,用于提供条件为假时的备用内容。

<div *ngIf="condition; else elseBlock">True</div>
<ng-template #elseBlock>False</ng-template>

AsyncPipe:
用于订阅可观察对象,并自动清理订阅。

<div>{{ (data$ | async)?.property }}</div>

NgNonBindable:
用于跳过元素及其子元素的Angular绑定。

<span ngNonBindable>{{ '{' }}{{ value }}{{ '}' }}</span>

NgContent:
用于在组件中分配内容(使用标签)。

NgHost:
用于在创建组件时指定宿主元素。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

我要成为算法高手-递归篇

目录 题目1&#xff1a;汉诺塔题目2&#xff1a;合并两个有序链表题目3&#xff1a;反转链表题目4&#xff1a;两两交换链表中的结点题目5&#xff1a;Pow(x,n) 题目1&#xff1a;汉诺塔 面试题 08.06. 汉诺塔问题 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1…

【大数据技术基础】 课程 第8章 数据仓库Hive的安装和使用 大数据基础编程、实验和案例教程(第2版)

第8章 数据仓库Hive的安装和使用 8.1 Hive的安装 8.1.1 下载安装文件 访问Hive官网&#xff08;http://www.apache.org/dyn/closer.cgi/hive/&#xff09;下载安装文件apache-hive-3.1.2-bin.tar.gz 下载完安装文件以后&#xff0c;需要对文件进行解压。按照Linux系统使用的…

js.二叉树的层序遍历2

链接&#xff1a;107. 二叉树的层序遍历 II - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值 自底向上的层序遍历 。 &#xff08;即按从叶子节点所在层到根节点所在的层&#xff0c;逐层从左向右遍历&#xff09…

kafka生产者和消费者命令的使用

kafka-console-producer.sh 生产数据 # 发送信息 指定topic即可 kafka-console-producer.sh \ --bootstrap-server bigdata01:9092 \ --topic topicA # 主题# 进程 29124 ConsoleProducer kafka-console-consumer.sh 消费数据 # 消费数据 kafka-console-consumer.sh \ --boo…

基于Springboot的心灵治愈交流平台系统的设计与实现

基于Springboot的心灵治愈交流平台系统 介绍 基于Springboot的心灵治愈交流平台系统&#xff0c;后端框架使用Springboot和mybatis&#xff0c;前端框架使用Vuehrml&#xff0c;数据库使用mysql&#xff0c;使用B/S架构实现前台用户系统和后台管理员系统&#xff0c;和不同级别…

从入门到精通数据结构----四大排序(上)

目录 首言&#xff1a; 1. 插入排序 1.1 直接插入排序 1.2 希尔排序 2. 选择排序 2.1 直接选择排序 2.2 堆排序 3. 交换排序 3.1 冒泡排序 3.2 快排 结尾&#xff1a; 首言&#xff1a; 本篇文章主要介绍常见的四大排序&#xff1a;交换排序、选择排序、插入排序、归并排…

SpringCloud+SpringCloudAlibaba学习笔记

SpringCloud 服务注册中心 eureka ap 高可用 分布式容错 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency><groupId…

Sentinel服务保护

Sentinel是阿里巴巴开源的一款服务保护框架&#xff0c;目前已经加入SpringCloudAlibaba中。官方网站&#xff1a; home | Sentinel Sentinel 的使用可以分为两个部分: 核心库&#xff08;Jar包&#xff09;&#xff1a;不依赖任何框架/库&#xff0c;能够运行于 Java 8 及以…

【Redis 】Bitmap 使用

Redis Bitmap介绍 Redis Bitmap 是一种特殊的数据类型&#xff0c;它通过字符串类型键来存储一系列连续的二进制位&#xff08;bits&#xff09;&#xff0c;每个位可以独立地表示一个布尔值&#xff08;0 或 1&#xff09;。这种数据结构非常适合用于存储和操作大量二值状态的…

【spark-spring boot】学习笔记

目录 说明RDD学习RDD介绍RDD案例基于集合创建RDDRDD存入外部文件中 转换算子 操作map 操作说明案例 flatMap操作说明案例 filter 操作说明案例 groupBy 操作说明案例 distinct 操作说明案例 sortBy 操作说明案例 mapToPair 操作说明案例 mapValues操作说明案例 groupByKey操作说…

C++ 红黑树:红黑树的插入及应用(map与set的封装)

目录 红黑树 红黑树的概念 红黑树的性质 红黑树节点的定义 一、如果默认给黑色 二、如果默认给红色 红黑树的插入操作 1.按搜索树的规则进行插入 2.检测新节点插入后&#xff0c;红黑树的性质是否造到破坏 情况一&#xff1a;cur为红&#xff0c;parent为红&#xff…

elementUI非常规数据格式渲染复杂表格(副表头、合并单元格)

效果 数据源 前端代码 (展示以及表格处理/数据处理) 标签 <el-table :data"dataList" style"width: 100%" :span-method"objectSpanMethod"><template v-for"(item, index) in headers"><el-table-column prop"…

HTML详解(1)

1.HTML定义 HTML&#xff1a;超文本标记语言。超文本&#xff1a;通过链接可以把多个网页链接到一起标记&#xff1a;标签&#xff0c;带括号的文本后缀&#xff1a;.html 标签语法&#xff1a;<strong>需加粗文字</strong> 成对出现&#xff0c;中间包裹内容&l…

两数之和--leetcode100题

一&#xff0c;前置知识 1&#xff0c;vector向量 二&#xff0c;题目 1. 两数之和https://leetcode.cn/problems/two-sum/ 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下…

微信小程序条件渲染与列表渲染的全面教程

微信小程序条件渲染与列表渲染的全面教程 引言 在微信小程序的开发中,条件渲染和列表渲染是构建动态用户界面的重要技术。通过条件渲染,我们可以根据不同的状态展示不同的内容,而列表渲染则使得我们能够高效地展示一组数据。本文将详细讲解这两种渲染方式的用法,结合实例…

李宏毅机器学习课程知识点摘要(14-18集)

线性回归&#xff0c;逻辑回归&#xff08;线性回归sigmoid&#xff09;&#xff0c;神经网络 linear regression &#xff0c; logistic regression &#xff0c; neutral network 里面的偏导的相量有几百万维&#xff0c;这就是neutral network的不同&#xff0c;他是…

Bean的生命周期详解保姆级教程,结合spring boot和spring.xml两种方式讲解,5/7/10大小阶段详细分析

文章目录 Spring Bean的生命周期一、为什么知道 Bean 的生命周期&#xff1f;二、生命周期大致了解三、详细分析生命周期3.1 ① 初步划分为 5 步&#xff1a;3.1.1 spring 框架中怎么理解3.1.2 spring boot 项目中怎么理解 3.2 ② 细分 5 步为 7 步&#xff1a;3.2.1 spring 框…

gRPC 双向流(Bidirectional Streaming RPC)的使用方法

gRPC 是一个支持多种语言的高性能 RPC 框架&#xff0c;拥有丰富的 API 来简化服务端和客户端的开发过程。gRPC 支持四种 RPC 类型&#xff1a;Unary RPC、Server Streaming RPC、Client Streaming RPC 和 Bidirectional Streaming RPC。下面是双向流 API 的使用方法。 双向流…

ffmpeg视频滤镜:替换部分帧-freezeframes

滤镜描述 freezeframes 官网地址 > FFmpeg Filters Documentation 这个滤镜接收两个输入&#xff0c;然后会将第一个视频中的部分帧替换为第二个视频的某一帧。 滤镜使用 参数 freezeframes AVOptions:first <int64> ..FV....... set first fra…

解决SpringBoot连接Websocket报:请求路径 404 No static resource websocket.

问题发现 最近在工作中用到了WebSocket进行前后端的消息通信&#xff0c;后端代码编写完后&#xff0c;测试一下是否连接成功&#xff0c;发现报No static resource websocket.&#xff0c;看这个错貌似将接口变成了静态资源来访问了&#xff0c;第一时间觉得是端点没有注册成…