NestJS 项目实战-权限管理系统开发(六)

本章节内容: 1. 使用 Docker 运行 Minio 服务; 2. 设置 Minio; 3. 在 NestJS 中引入 Minio 服务与预签名接口。

本系列教程将教你使用 NestJS 构建一个生产级别的 REST API 风格的权限管理后台服务。

该教程主要包含以下内容:

  1. 用户登录,包含身份验证、无感刷新 token、单点登录;
  2. 用户、角色、权限的增删改查;
  3. 接口级别的权限控制,使用装饰器与守卫实现;
  4. 接口返回数据格式统一,使用拦截器与异常过滤器实现;
  5. 使用 Winston 进行日志管理;
  6. Minio 的使用,包含文件上传预签名等;
  7. 编写 Swagger API 文档;
  8. 数据库设计与 Prisma 建模
  9. 单元测试;
  10. 生产环境部署,使用 Docker

主要技术栈:NestJS、TS、PostgreSQL、Prisma、Redis、Minio、Winston、Docker。

代码仓库在线预览地址,账号:test,密码:d.12345

1. 使用 Docker 运行 Minio 服务

打开 docker-compose.yml 文件,添加以下内容:

ts 复制代码
...

minio:
    image: bitnami/minio:latest
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - minio_data:/data
    environment:
      MINIO_ROOT_USER: wansongtao
      MINIO_ROOT_PASSWORD: w.12345.st
      MINIO_DEFAULT_BUCKETS: avatar
      
volumes:
  ...
  minio_data:

重新运行 docker-compose --env-file .env.development up --build 命令构建容器。

在浏览器中输入 http://localhost:9001/ 网址,就可以看到 Minio 的管理界面了。

2. 设置 Minio

首先输入我们在 docker-compose.yml 中设置的账号密码,登录进入 Minio 的管理后台网站。

然后我们需要添加一个 Access Keys ,后续通过 NestJS 访问这个服务时需要。先点击左边菜单栏的 Access Keys,再点击右边的 Create access key 按钮。 如图所示。

保存好 Access KeySecret Key,后续需要用到。

最后还需要调整一下桶的访问策略,按下图所示操作:

3. 在 NestJS 中引入 Minio 服务

3.1 添加环境变量配置

首先,在 .env.development 中添加相关环境变量配置:

env 复制代码
# Minio
MINIO_END_POINT="localhost"
MINIO_PORT=9000
MINIO_USE_SSL=false
MINIO_ACCESS_KEY="..."
MINIO_SECRET_KEY="..."
MINIO_BUCKET_NAME="avatar"
MINIO_EXPIRES_IN=120

其次,在 /src/common/config/index.ts 中添加相应的常量:

ts 复制代码
  minio: {
    endPoint: configService.get<string>('MINIO_END_POINT'),
    port: +configService.get<number>('MINIO_PORT'),
    useSSL: configService.get('MINIO_USE_SSL') === 'true',
    accessKey: configService.get<string>('MINIO_ACCESS_KEY'),
    secretKey: configService.get<string>('MINIO_SECRET_KEY'),
    bucketName: configService.get<string>('MINIO_BUCKET_NAME'),
    expiresIn: +configService.get<number>('MINIO_EXPIRES_IN'),
  },

3.2 新建 Upload 模块

接下来在项目根目录新开一个终端窗口,输入 nest g res upload 命令,新建一个 upload 模块。

然后安装 Minio 库,输入 pnpm i minio

最后,打开 /src/upload/upload.service.ts 文件添加以下代码:

ts 复制代码
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { getBaseConfig } from 'src/common/config';
import { Client } from 'minio';

@Injectable()
export class UploadService {
  private minioClient: Client;

  constructor(private readonly configService: ConfigService) {
    const config = getBaseConfig(configService);

    this.minioClient = new Client({
      endPoint: config.minio.endPoint,
      port: config.minio.port,
      useSSL: config.minio.useSSL,
      accessKey: config.minio.accessKey,
      secretKey: config.minio.secretKey,
    });
  }
}

启动开发环境,没有报错则代表连上 Minio 服务了。

注意:要先运行相关 docker 服务哦。

3.3 添加预签名接口

首先,打开 /src/upload/upload.service.ts 文件添加一个预签名方法:

ts 复制代码
  async presignedUrl(fileName: string) {
    const config = getBaseConfig(this.configService);

    const url = await this.minioClient.presignedPutObject(
      config.minio.bucketName,
      fileName,
      config.minio.expiresIn,
    );

    return { presignedUrl: url };
  }

该方法接收一个文件名参数,返回一个上传文件链接。

其次,新建一个 /src/upload/dto/presigned.dto.ts 文件并添加以下内容:

ts 复制代码
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString } from 'class-validator';

export class PresignedDto {
  @IsString({ message: '文件名必须是字符串' })
  @IsNotEmpty({ message: '文件名不能为空' })
  @ApiProperty({ description: '文件名' })
  filename: string;
}

DTO 将用来校验接口参数。

然后,新建一个 /src/upload/entities/presigned.entity.ts 文件并添加以下内容:

ts 复制代码
import { ApiProperty } from '@nestjs/swagger';

export class PresignedEntity {
  @ApiProperty({
    description: '预签名 URL',
  })
  presignedUrl: string;
}

该实体将用作接口返回对象。

最后,修改 /src/upload/upload.controller.ts 文件的内容为:

ts 复制代码
import { Body, Controller, Post } from '@nestjs/common';
import { UploadService } from './upload.service';
import { ApiOperation } from '@nestjs/swagger';
import { ApiBaseResponse } from 'src/common/decorator/api-base-response.decorator';
import { PresignedDto } from './dto/presigned.dto';
import { PresignedEntity } from './entities/presigned.entity';

@Controller('upload')
export class UploadController {
  constructor(private readonly uploadService: UploadService) {}

  @ApiOperation({ summary: '获取预签名 URL' })
  @ApiBaseResponse(PresignedEntity)
  @Post('presigned')
  presignedUrl(@Body() presignedDto: PresignedDto): Promise<PresignedEntity> {
    return this.uploadService.presignedUrl(presignedDto.filename);
  }
}

至此,文件预签名接口就开发完成了。运行开发环境后,可以用 postman 之类的工具测试该接口是否能返回预签名 URL,然后再测试能否通过预签名 URL 将图片文件上传到 minio。

接口的单元测试代码请查看仓库

相关推荐
盛派网络小助手1 小时前
微信 SDK 更新 Sample,NCF 文档和模板更新,更多更新日志,欢迎解锁
开发语言·人工智能·后端·架构·c#
∝请叫*我简单先生1 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl
zquwei2 小时前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
dessler3 小时前
Docker-run命令详细讲解
linux·运维·后端·docker
Q_19284999063 小时前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
蜜獾云3 小时前
npm淘宝镜像
前端·npm·node.js
dz88i83 小时前
修改npm镜像源
前端·npm·node.js
ZSYP-S4 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
Yuan_o_4 小时前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端