Nestjs全网最佳翻译-概况-管道-Pipes

news2024/9/21 20:41:22

管道

带上装饰器 @Injectable() 并实现了 PipeTransform 接口的类,就是管道。

来自静态目录的图像

管道有 2 个典型的应用场景:

数值转换:将输入的参数转换成目标类型,例如,string to number。
数值校验:对输入的参数进行校验,如果符合要求则直接通过,否则抛出异常。

管道所处理的参数和控制器路由处理程序处理的参数是相同参数。Nest 在一个方法被调用之前插入了一个管道,该管道接收方法的参数并对其进行操作。任何转换或验证操作都是在这个时候进行的,然后用转换过的参数来调用路由处理器。

Nest 有一组开箱即用的内置管道,你也可以定制自己的管道。这一章节我们将介绍内置管道,并展示如何将它们与路由处理程序绑定。然后,我们将定制几个管道,以展示你如何从头开始建立一个管道。

管道如果抛出异常,异常层会捕获该异常,捕获后,控制器处理方法将不会再执行。这给了你一个最佳实践的技术,用于验证从系统边界的外部来源进入应用程序的数据。

内置管道

Nest 有 9 个内置管道:

ValidationPipe
ParseIntPipe
ParseFloatPipe
ParseBoolPipe
ParseArrayPipe
ParseUUIDPipe
ParseEnumPipe
DefaultValuePipe
ParseFilePipe

这些内置管道,都位于 @nestjs/common 包。

让我们快速看一下使用 ParseIntPipe 的情况。这是一个转换用例,管道确保方法处理程序参数被转换为一个 JavaScript 整数(或者在转换失败时抛出一个异常)。在本章的后面,我们将展示 ParseIntPipe 的一个简单的自定义实现。下面的示例技术也适用于其他内置的转换管道(ParseBoolPipe、ParseFloatPipe、ParseEnumPipe、ParseArrayPipe 和 ParseUUIDPipe,我们在本章中将它们称为 Parse*管道)。

绑定管道

为了使用管道,我们需要将管道类的一个实例绑定到函数上。在 ParseIntPipe 例子中,我们想把管道与一个特定的路由处理方法联系起来,并确保它在该方法被调用之前运行。我们通过下面的结构来实现这一目的,我们将其称为在方法参数层绑定管道:

@Get(':id')
async findOne(@Param('id', ParseIntPipe) id: number) {
  return this.catsService.findOne(id);
}

如上设置后,要么 findOne()方法中收到的参数是一个数字,要么在调用路由处理程序之前抛出一个异常。

我们请求下这个接口:

GET localhost:3000/abc

Nest 将抛出异常:

{
  "statusCode": 400,
  "message": "Validation failed (numeric string is expected)",
  "error": "Bad Request"
}

这个异常将阻止 findOne()方法的主体执行。

在上面的例子中,我们传递了一个 ParseIntPipe 类,而不是一个实例,把实例化的责任留给了框架,并实现了依赖注入。就像管道和守卫一样,我们也可以传递一个实例。如果我们想通过传递选项来定制内置管道的行为,传递一个实例是非常有用的:

@Get(':id')
async findOne(
  @Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }))
  id: number,
) {
  return this.catsService.findOne(id);
}

绑定其他转换管道(所有 Parse*管道)的工作原理类似。这些管道都是在验证路由参数、查询字符串参数和请求体值的背景下工作的。

例如,用一个查询字符串参数:

@Get()
async findOne(@Query('id', ParseIntPipe) id: number) {
  return this.catsService.findOne(id);
}

下面是一个使用 ParseUUIDPipe 来解析一个字符串参数并验证它是否是 UUID 的例子。

@Get(':uuid')
async findOne(@Param('uuid', new ParseUUIDPipe()) uuid: string) {
  return this.catsService.findOne(uuid);
}

当使用 ParseUUIDPipe()时,你正在解析版本 3、4 或 5 的 UUID,如果你只需要一个特定版本的 UUID,你可以在管道选项中传递一个版本。

上面我们看到了绑定各种 Parse*系列内置管道的例子。绑定验证管道有点不同,我们将在下一节讨论。

另外,请参阅验证技术,了解验证管道的大量实例。

自定义管道

如前所述,你可以建立自己的自定义管道。虽然 Nest 提供了强大的内置 ParseIntPipe 和 ValidationPipe,但让我们从头开始构建每个的简单自定义版本,看看如何构建自定义管道。

我们从一个简单的 ValidationPipe 开始。最初,我们会让它简单地接受一个输入值并立即返回相同的值,表现得像一个独立函数。

import { PipeTransform, Injectable, ArgumentMetadata } from "@nestjs/common";

@Injectable()
export class ValidationPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    return value;
  }
}

PipeTransform<T, R>是一个泛型接口。该接口使用 T 来表示输入值的类型,使用 R 来表示 transform()方法的返回类型。

每个管道都必须实现 transform()方法以实现 PipeTransform 接口。这个方法有两个参数:

value
metadata

value 参数是当前处理的方法参数(在它被路由处理方法接收之前),而 metadata 数据是当前处理的方法参数的元数据。元数据对象有这些属性:

export interface ArgumentMetadata {
  type: "body" | "query" | "param" | "custom";
  metatype?: Type<unknown>;
  data?: string;
}

这些属性描述了当前处理的参数

参数说明
type指定参数类型,body @Body(), query @Query(), param @Param() 或自定义参数,详细看这里
metatype提供参数的元类型,例如,字符串。注意:如果你在路由处理方法签名中省略了类型声明,或者使用 vanilla JavaScript,那么这个值是未定义的。
data传递给装饰器的字符串,例如@Body(‘string’)。如果你让装饰器的括号内参数为空,则未定义

TypeScript 接口在转译过程中消失。因此,如果一个方法参数的类型被声明为一个接口而不是一个类,元类型的值将是 Object。

基于模式的验证

以下演示对于请求结构体的参数验证,请求方法如下:

@Post()
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}

结构体 CreateCatDto 如下:

export class CreateCatDto {
  name: string;
  age: number;
  breed: string;
}

我们要确保任何进入创建方法的请求都包含一个有效的主体。所以我们必须验证 createCatDto 对象的三个成员变量。我们可以在路由处理方法中完成这个工作,但这样做并不理想,因为它将破坏单一责任规则(SRP)。

另一种方法是创建一个验证器类并将任务委托给它。这样做的缺点是我们必须记住在每个方法的开头调用这个验证器。

创建验证中间件怎么样?这也行得通,但不幸的是,不可能创建通用的中间件,可以在整个应用程序的所有上下文中使用。这是因为中间件不知道执行环境,包括将被调用的处理程序和它的任何参数。

当然,这正是管道设计的用例。因此,让我们继续完善我们的验证管道。(啰嗦了一大堆)

对象模式验证

有几种方法可用于以干净、干燥的方式进行对象验证。一种常见的方法是使用基于模式的验证。让我们继续尝试这种方法。

Joi 库允许你以一种直接的方式创建模式,并有一个可读的 API。让我们建立一个验证管道,利用基于 Joi 的模式。

首先,安装所需的软件包:

npm install --save joi

在下面的代码示例中,我们创建了一个简单的类,将模式作为构造函数参数。然后我们应用 schema.validate()方法,根据所提供的模式验证我们传入的参数。

如前所述,一个验证管道要么返回不变的值,要么抛出一个异常。

在下一节中,你将看到我们如何使用@UsePipes()装饰器为一个给定的控制器方法提供适当的模式。这样做使得我们的验证管道可以在不同的上下文中重复使用,就像我们设计的那样。(直接看代码还理解的快些)

import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { ObjectSchema } from 'joi';

@Injectable()
export class JoiValidationPipe implements PipeTransform {
  constructor(private schema: ObjectSchema) {}

  transform(value: any, metadata: ArgumentMetadata) {
    const { error } = this.schema.validate(value);
    if (error) {
      throw new BadRequestException('Validation failed');
    }
    return value;
  }

绑定验证管道

早些时候,我们看到了如何绑定转换管道(如 ParseIntPipe 和其他 Parse*管道)。

绑定验证管道也是非常直接的。

在这种情况下,我们要在方法调用层面上绑定管道。在我们目前的例子中,我们需要做以下工作来使用 JoiValidationPipe:

创建一个 JoiValidationPipe 的实例
在管道的类构造函数中传递上下文特定的 Joi 模式
将该管道与方法绑定
Joi 模式的例子:

export const createCatSchema = Joi.object({
  name: Joi.string().required(),
  age: Joi.number().required(),
  breed: Joi.string().required(),
});

export interface CreateCatDto {
  name: string;
  age: number;
  breed: string;
}

我们使用@UsePipes()装饰器来做到这一点,如下所示:

@Post()
@UsePipes(new JoiValidationPipe(createCatSchema))
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}

@UsePipes() 装饰器是从 @nestjs/common 包中导入的。

类校验器

本节中的技术需要 TypeScript,如果你的应用程序是用 JavaScript 编写的,则无法使用。

让我们来看看我们的验证技术的另一种实现方式。

Nest 与 class-validator 库配合得很好。这个强大的库允许你使用基于装饰器的验证。基于装饰器的验证是非常强大的,特别是当与 Nest 的 Pipe 功能相结合时,因为我们可以访问所处理的属性的元类型。在我们开始之前,我们需要安装所需的包:(又是啰嗦的一堆)

npm i --save class-validator class-transformer

一旦这些都安装完毕,我们就可以给 CreateCatDto 类添加一些装饰器。在这里,我们看到了这种技术的一个显著优势:CreateCatDto 类仍然是我们的 Post 主体对象的唯一真理来源(而不是必须创建一个单独的验证类)。(加一些装饰器在字段上面)

import { IsString, IsInt } from "class-validator";

export class CreateCatDto {
  @IsString()
  name: string;

  @IsInt()
  age: number;

  @IsString()
  breed: string;
}

在这里关于类验证器装饰器的信息。

现在我们可以创建一个使用这些注解的 ValidationPipe 类。

import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';

@Injectable()
export class ValidationPipe implements PipeTransform<any> {
  async transform(value: any, { metatype }: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }
    const object = plainToInstance(metatype, value);
    const errors = await validate(object);
    if (errors.length > 0) {
      throw new BadRequestException('Validation failed');
    }
    return value;
  }

  private toValidate(metatype: Function): boolean {
    const types: Function[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }
}

让我们来看看这段代码。首先,注意 transform()方法被标记为异步。这是有可能的,因为 Nest 同时支持同步和异步管道。我们使这个方法成为异步的,因为一些类验证器的验证可以是异步的(利用 Promises)。

接下来请注意,我们正在使用析构法来提取元类型字段(从 ArgumentMetadata 中只提取这个成员)到我们的元类型参数。这只是获取完整的 ArgumentMetadata 的缩写,然后有一个额外的语句来分配 metatype 变量。

接下来,注意辅助函数 toValidate()。它负责绕过验证步骤,如果当前正在处理的参数是一个本地的 JavaScript 类型时,验证就会直接返回(这些参数不能附加验证装饰器,所以没有理由通过验证步骤运行它们)。

接下来,我们使用类转换函数 plainToInstance()将我们的普通 JavaScript 参数对象转换为类型化的对象,以便我们可以应用验证。我们必须这样做的原因是,当从网络请求反序列化时,传入的 post body 对象没有任何类型信息(这是底层平台的工作方式,如 Express)。Class-validator 需要使用我们之前为 DTO 定义的验证装饰器,所以我们需要进行这种转换,将传入的主体作为一个适当的装饰对象,而不仅仅是一个普通的对象。

最后,如前所述,由于这是一个验证管道,它要么不变地返回值,要么抛出一个异常。

最后一步是绑定 ValidationPipe。管道可以是参数范围的,方法范围的,控制器范围的,或者全局范围的。早些时候,在我们基于 Joi 的验证管道中,我们看到了一个在方法层绑定管道的例子。在下面的例子中,我们将把管道实例绑定到路由处理程序@Body()装饰器上,以便我们的管道被调用来验证 post body。

@Post()
async create(
  @Body(new ValidationPipe()) createCatDto: CreateCatDto,
) {
  this.catsService.create(createCatDto);
}

全局范围的管道

由于 ValidationPipe 被创建为尽可能的通用,我们可以通过把它设置为全局范围的管道来实现它的全部效用,这样它就会被应用于整个应用程序的每一个路由处理程序。

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}
bootstrap();

在混合型应用程序中,useGlobalPipes()方法不能使用在网关和微服务上。对于 “标准”(非混合型)微服务应用程序,useGlobalPipes()确实可以进行全局性的管道设置。

全局管道被用于整个应用程序,用于每个控制器和每个路由处理程序。

请注意,在依赖注入方面,从任何模块之外注册的全局管道(如上面的例子中使用 useGlobalPipes())不能注入依赖,因为绑定是在任何模块的上下文之外完成的。为了解决这个问题,你可以使用下面的结构直接从任何模块设置一个全局管道:

import { Module } from "@nestjs/common";
import { APP_PIPE } from "@nestjs/core";

@Module({
  providers: [
    {
      provide: APP_PIPE,
      useClass: ValidationPipe,
    },
  ],
})
export class AppModule {}

当使用这种方法对管道进行依赖注入时,请注意,无论在哪个模块采用这种结构,管道实际上都是全局的。这应该在哪里进行呢?选择定义管道(上例中的 ValidationPipe)的模块。另外,useClass 并不是处理自定义提供者注册的唯一方法。在这里了解更多。

内置的 ValidationPipe

作为提醒,你不必自己建立一个通用的验证管道,因为 Nest 提供了开箱即用的 ValidationPipe。内置的 ValidationPipe 提供了比我们在本章中构建的样本更多的选项,为了说明自定义管道的机制,我们保留了基本的选项。你可以在这里找到完整的细节,以及大量的例子。

转换用例

验证并不是自定义管道的唯一用例。在本章的开头,我们提到管道还可以将输入的数据转换为所需的格式。这是可能的,因为从转换函数返回的值会完全覆盖参数的先前值。

这在什么时候是有用的?考虑到有时从客户端传来的数据需要进行一些改变–例如将一个字符串转换成一个整数–然后才能被路由处理方法正确处理。此外,一些必要的数据字段可能缺失,我们希望应用默认值。转化管道可以通过在客户端请求和请求处理程序之间插入一个处理函数来执行这些功能。

下面是一个简单的 ParseIntPipe,它负责将一个字符串解析为一个整数值。(如上所述,Nest 有一个内置的 ParseIntPipe,它更复杂;我们把它作为自定义转换管道的一个简单例子)。

import {
  PipeTransform,
  Injectable,
  ArgumentMetadata,
  BadRequestException,
} from "@nestjs/common";

@Injectable()
export class ParseIntPipe implements PipeTransform<string, number> {
  transform(value: string, metadata: ArgumentMetadata): number {
    const val = parseInt(value, 10);
    if (isNaN(val)) {
      throw new BadRequestException("Validation failed");
    }
    return val;
  }
}

然后我们可以将这个管道与所选参数绑定,如下图所示:

@Get(':id')
async findOne(@Param('id', new ParseIntPipe()) id) {
  return this.catsService.findOne(id);
}

另一个有用的转换案例是使用请求中提供的 ID 从数据库中选择一个现有的用户实体:

@Get(':id')
findOne(@Param('id', UserByIdPipe) userEntity: UserEntity) {
  return userEntity;
}

我们把这个管道的实现留给读者,但请注意,像所有其他转换管道一样,它接收一个输入值(一个 id)并返回一个输出值(一个 UserEntity 对象)。通过将处理程序中的模板代码抽象到一个公共管道中,这可以使你的代码更加声明化和简洁。

提供默认值

Parse*管道期望一个参数的值被定义。在收到空值或未定义的值时,它们会抛出一个异常。为了让端点能够处理缺失的查询系统参数值,我们必须提供一个默认值,在 Parse*管道对这些值进行操作之前注入。DefaultValuePipe 就可以达到这个目的。只需在相关 Parse*管道之前的@Query()装饰器中实例化一个 DefaultValuePipe,如下所示:

@Get()
async findAll(
  @Query('activeOnly', new DefaultValuePipe(false), ParseBoolPipe) activeOnly: boolean,
  @Query('page', new DefaultValuePipe(0), ParseIntPipe) page: number,
) {
  return this.catsService.findAll({ activeOnly, page });
}

总结

介绍了管道的 2 中常用场景:数据验证和数据转换。

介绍了一组内置管道,以及如何自定义管道。

分别使用 joi 和 class-validator class-transformer,2 种方式举例实现数据验证。

介绍如何设置全局管道。

介绍举例实现数据转换。

介绍如何设置默认值。

示例代码请参考Github 欢迎 star。

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

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

相关文章

cocos creator v3.6版本使用Intersection2D模块的circleCircle方法

在cocos creator v3版本中Intersection2D模块的circleCircle方法可以用来检测两个圆形是否相交 该方法可以实现的功能有&#xff1a; cocos creator吸铁石实现、cocos creator物体在固定位置吸附、cocos creator物体吸附效果、cocos creator吸铁石实现、cocos creator两个物体时…

统计软件与数据分析Lesson9----爬虫解析库Beautiful Soup

统计软件与数据分析Lesson9----爬虫解析库Beautiful Soup知识点总结 1.requests 模块1.1 查看requests功能函数1.2 发送请求1.3 传递URL参数1.4 获取响应内容 2.Beautiful Soup模块2.1 解析器2.2 对象类型2.2.1 Beautiful Soup2.2.2 标签Tag2.2.3 可遍历的字符串NavigableStrin…

Java——包含min函数的栈

题目链接 牛客在线oj题——包含min函数的栈 题目描述 定义栈的数据结构&#xff0c;请在该类型中实现一个能够得到栈中所含最小元素的 min 函数&#xff0c;输入操作时保证 pop、top 和 min 函数操作时&#xff0c;栈中一定有元素。 此栈包含的方法有&#xff1a; push(va…

SRv6实践项目(六):控制面完成链路和主机的发现

在本次实验中&#xff0c;我们需要利用ONOS完成对数据面的控制 1.使能packet的IO功能&#xff0c;验证链路发现 main.p4提供了和P4Runtime的通信的消息的定义格式&#xff0c;分别是PacketIn和PacketOut&#xff0c;他们都被加上了一个注解&#xff0c;表示这是一个控制器交互…

c++篇---缺省参数

文章目录 一、缺省参数概念二、缺省参数实例三、缺省参数声明和定义四、全缺省和半缺省 一、缺省参数概念 缺省参数 在调用该函数时&#xff0c;如果实参没有指定传内容&#xff0c;那么在函数中用形参时&#xff0c;就采用为函数参数指定的这个缺省值 但是如果在调用该函数时…

【Qt 实现一个画板,基于QWidget,可以绘制直线和矩形】

【Qt 实现一个画板&#xff0c;基于QWidget,可以绘制直线和矩形】 简介效果展示源码mainwindow.hmainwindow.cpppainterwidget.hpainterwidget.cppshape.h &#xff08;管理&#xff09;line.hline.cpprect.hrect.cpp 结 &#x1f649;&#x1f649;更多内容 点击&#xff1a;Q…

力扣sql中等篇练习(七)

力扣sql中等篇练习(七) 1 查询活跃业务 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # Write your MySQL query statement below # 先求出所有业务的平均发生次数 SELECT t2.business_id FROM (SELECT e.*,IF(e.occurences>t1.A_NUM,1,0) tota…

【C++】vector的简化模拟实现

文章目录 1. 主要结构2. 默认成员函数3. 迭代器4. 容量相关1. size和capacity2. reserve3. resize 5. 数据访问6. 数据修改1. push_back2.pop_back3. insert4.erase5.swap6.clear 1. 主要结构 参照SGI版本的vector实现&#xff0c;使用三个指针来维护这样一段内存空间 templa…

ACL访问控制列表简介和配置演示

一.ACL功能和特点 1.功能 2.特点 二.ACL种类 1.基础ACL&#xff1a; 2.增强ACL&#xff1a; 三.配置演示 1.基础ACL&#xff1a; 2.增强ACL&#xff1a; 一.ACL功能和特点 1.功能 对感兴趣的路由 (控制层面)进行设置策略 对感兴趣的流量 (数据层面)进行设置策略 2.…

Activity启动模式的生命周期

四种启动模式 1.standard android:launchMode"standard" 默认的标准启动模式&#xff0c;每次启动当前Activity&#xff0c;任务栈中都添加一个当前Activity的实例。按返回键时&#xff0c;表现出退出多个当前Activity的现象。 MainActivityOne和MainActivityTwo都…

DPText-DETR原理及源码解读

一、原理 发展脉络&#xff1a;DETR是FACEBOOK基于transformer做检测开山之作&#xff0c;Deformable DETR加速收敛并对小目标改进&#xff0c;TESTR实现了端到端的文本检测识别&#xff0c;DPText-DETR做了精度更高的文字检测。 DETR 2020 FACEBOOK&#xff1a; 原理 https://…

c/c++:函数的作用,分类,随机数,函数定义,调用,申明,exit()函数,多文件编程,防止头文件重复

c/c&#xff1a;函数的作用&#xff0c;分类&#xff0c;随机数&#xff0c;函数定义&#xff0c;调用&#xff0c;申明&#xff0c;exit()函数&#xff0c;多文件编程&#xff0c;防止头文件重复 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大…

Spring启动及Bean实例化过程来看经典扩展接口

目录 一、Spring启动及Bean实例化过程 二、分析其对应经典扩展接口 三、对开发的指导意义 备注&#xff1a;以下总结只是一些基本的总结思路&#xff0c;具体每个扩展接口的应用后续进行分析总结。 一、Spring启动及Bean实例化过程 Spring启动及Bean实例化的过程&#xff0…

6 款顶级 Android 数据恢复软件列表

数据丢失可能会扰乱您的个人/企业生活&#xff0c;如果手动完成&#xff0c;可能很难恢复丢失的数据。Android 数据恢复软件是解决此问题的完美解决方案。这些工具可帮助您快速轻松地从 Android 设备恢复丢失的数据。它可以帮助您恢复照片、视频、笔记、联系人等。 我研究了市…

1. C++使用Thread类创建多线程的三种方式

1. 说明 使用Thread类创建线程对象的同时就会立刻启动线程&#xff0c;线程启动之后就要明确是等待线程结束&#xff08;join&#xff09;还是让其自主运行&#xff08;detach&#xff09;&#xff0c;如果在线程销毁前还未明确上面的问题&#xff0c;程序就会报错。一般都会选…

webserve简介

目录 I/O分类I/O模型阻塞blocking非阻塞 non-blocking&#xff08;NIO&#xff09;IO复用信号驱动异步 webServerHTTP简介概述工作原理HTTP请求头格式HTTP请求方法HTTP状态码 服务器编程基本框架两种高效的事件处理模式Reactor模式Proactor模拟 Proactor 模式 线程池 I/O分类 …

字节岗位薪酬体系曝光,看完感叹:不服真不行

曾经的互联网是PC的时代&#xff0c;随着智能手机的普及&#xff0c;移动互联网开始飞速崛起。而字节跳动抓住了这波机遇&#xff0c;2015年&#xff0c;字节跳动全面加码短视频&#xff0c;从那以后&#xff0c;抖音成为了字节跳动用户、收入和估值的最大增长引擎。 自从字节…

最全MySQL8.0实战教程

文章目录 最全MySQL8.0实战教程一.前言1.计算机语言概述2.SQL的概述2.1 语法特点2.2 MySQL的安装2.2.1 方式1&#xff1a;解压配置方式2.2.2 方式2&#xff1a;步骤安装方式 二. 数据库DDL操作1.DDL概念2.对数据库常用操作 最全MySQL8.0实战教程 长路漫漫&#xff0c;键盘为伴&…

【Linux进阶篇】启动流程和服务管理

目录 &#x1f341;系统启动 &#x1f343;Init和Systemd的区别 &#x1f343;运行级别和说明 &#x1f341;Systemd服务管理 &#x1f343;6和7命令区别 &#x1f343;systemd常用命令 &#x1f341;系统计划调度任务 &#x1f343;一次性任务-at &#x1f343;batch &#x1…

论文 : Multi-Channel EEG Based Emotion Recognition Using TCNBLS

Multi-Channel EEG Based Emotion Recognition Using Temporal Convolutional Network and Broad Learning System 本文设计了一种基于多通道脑电信号的端到端情绪识别模型——时域卷积广义学习系统(TCBLS)。TCBLS以一维脑电信号为输入&#xff0c;自动提取脑电信号的情绪相关…