【NestJS实战】图片上传与下载上传 未使用数据库,暂且直接存 先装两个包 npm i multer -S 、npm
上传
- 未使用数据库,暂且直接存
- 先装两个包
npm i multer -S
、npm i @types/multer -D
- 在 upload.module.ts 中引入
import { Module } from '@nestjs/common';
import { UploadService } from './upload.service';
import { UploadController } from './upload.controller';
import { MulterModule } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname } from 'path'
const path = require('path')
@Module({
controllers: [UploadController],
providers: [UploadService],
//! 注册 MulterModule
imports: [MulterModule.register({
//! 配置文件存储位置、文件重命名
storage: diskStorage({
destination: path.resolve(__dirname, '../images'),
filename: (_, file, callback) => {
// 文件名修改为时间戳,后缀名直接截取原文件的
const rename = `${new Date().getTime()}${extname(file.originalname)}`
return callback(null, rename)
}
})
})]
})
export class UploadModule {}
- 在控制器 upload.controller.ts 中,接受 /upload/pic 的请求,使用 express 内置的文件拦截器 FileInterceptor ,去拦截指定字段的数据,例如我这里叫做 picFile。结合上装饰器UseInterceptor、UploadedFile
import { Controller, Post, UseInterceptors, UploadedFile } from '@nestjs/common';
import { UploadService } from './upload.service';
import { UpdateUploadDto } from './dto/update-upload.dto';
import { FileInterceptor } from '@nestjs/platform-express';
@Controller('upload')
export class UploadController {
constructor(private readonly uploadService: UploadService) {}
//! 接收 /upload/pic 的请求
@Post('pic')
//! 文件必须使用拦截器,拦截的字段为picFile
@UseInterceptors(FileInterceptor('picFile'))
// 参数装饰器 UploadedFile ,用于提取文件信息
create(@UploadedFile() file) {
return this.uploadService.create(file);
}
}
- 在服务 upload.service.ts 中,使用参数对象file就能获取到图片保存的路径
import { Injectable } from '@nestjs/common';
@Injectable()
export class UploadService {
create(file) {
console.log('打印file', file)
return {
code: 200,
result: '上传成功'
};
}
}
- 提供一个静态资源的路径,让前端可以直接访问上传的文件。在 main.ts 中,用 useStaticAssets() 配置静态资源目录,第二个参数是虚拟路径,可选
没有虚拟路径:
有虚拟路径:
图片下载
方式1:直接使用url下载
后端
在控制器 download.controller.ts 中,接收 /download/byUrl 的请求。在服务 download.service.ts 中,直接获取文件路径,并用响应对象的 .download() 方法发出去
前端
直接打开一个窗口即可下载
<template>
<button @click="handleDownByUrl">使用url下载</button>
</template>
<script setup>
const handleDownByUrl = () => {
window.open('http://localhost:3000/download/byURL')
}
</script>
方式2:使用二进制流
后端
- 在控制器 download.controller.ts 中,接收 /download/byBinary 的请求。
- 在服务 download.service.ts 中
- new一个 zip.Stream 对象,它将图片压缩成二进制格式的.zip包
- 获取图片的路径,使用zip.Stream 对象将其转换为二进制
- 最后调用zip.Stream 对象的 .pipe() 将文件返回出去
前端
-
将响应的二进制数据转换为 Blob 格式
-
使用 URL.createObjectURL() 将其转为url字符串
-
url字符串塞入a标签的href属性
-
手动触发a标签的点击事件
<template>
<button @click="handleDownByBinary">使用二进制下载</button>
</template>
<script setup>
const handleDownByBinary = async () => {
// 1. 发请求获取二进制文件
const response = await fetch('http://localhost:3000/download/byBinary')
// 2. 调用响应对象的 arrayBuffer 方法,将后端的返回值读取为ArrayBuffer
const arrayBuffer = await response.arrayBuffer()
// 3. 转为Blob
const blob = new Blob([arrayBuffer])
// 4. 再转换为一条url
const urlStr = URL.createObjectURL(blob)
// 5. urlStr塞入a标签的href属性中
const a = document.createElement('a')
a.href = urlStr
a.download = 'zhouziyan.zip'
document.body.appendChild(a) // 插入页面
// 6. 手动触发点击事件
a.click()
document.body.removeChild(a); // 下载后清理
URL.revokeObjectURL(urlStr); // 释放URL对象
}
</script>
转载自:https://juejin.cn/post/7400609489789829159