开发背景
任何一个成熟的网站都少不了文件上传,我的个人博客也不例外,为了方便修改头像、上传文章封面,所以来开发这么一个文件上传的接口。
开始开发
安装依赖
这里我们需要设置静态资源目录,让NestJS
知道我们要上传到哪个目录下。
npm i @nestjs/serve-static @nestjs/platform-express
依赖配置
在我们的modules
中进行静态资源
目录的配置,这里我放在app.module.ts
中。
// ...
import { ServeStaticModule } from "@nestjs/serve-static";
import { join } from "path";
@Module({
imports: [
ServeStaticModule.forRoot({
rootPath: join(__dirname, "../", "public"),
}),
],
//...
})
export class ApiModule {}
首先引入静态资源模型
和path.join
。
在Module
注解中imports
引入静态资源模型
,并进行配置,使用join
方法组合路径
设置静态资源的根目录(rootPath
)为src/public
目录下。
Controller实现
首先定义Controller
骨架,我这里目前封装有一个基类BaseController
,所以UploadController
就继承这个BaseController
,并且先引入UploadService
,稍后再来定义。
import { Controller } from "@nestjs/common";
import { BaseControlle } from "../core/base.controller";
import { UploadService } from "../service/upload.service";
@Controller("upload")
export class UploadController extends BaseControlle {
constructor(private readonly uploadService: UploadService) {
super();
}
}
类
中定义文件上传的方法,因为该接口是post
请求,所以先引入Post注解
,在接口方法uploadLocal
内将操作抛给service
去处理。
import { Controller, Post } from "@nestjs/common";
import { BaseControlle } from "../core/base.controller";
import { UploadService } from "../service/upload.service";
@Post("local")
uploadLocal() {
return this.uploadService.uploadLocal();
}
抛给service
时一定要将请求参数
一同抛过去,里面含有上传的文件信息
,需要引入UploadedFiles注解
拿到参数request
。
import {
// ...
UseInterceptors
} from "@nestjs/common";
// ...
uploadLocal(@UploadedFiles() request) {
return this.uploadService.uploadLocal(request);
}
此时如果我们想设置上传的文件数量
、修改上传name
、添加额外的参数
时,需要引入nestjs
的拦截器UseInterceptors
和文件拦截器FileFieldsInterceptor
,并进行设置。
import {
// ...
UseInterceptors
} from "@nestjs/common";
// ...
@UseInterceptors(FileFieldsInterceptor([
{ name: "file", maxCount: 1 },
{ name: "custom", }
]))
uploadLocal(@UploadedFiles() request) {
return this.uploadService.uploadLocal(request);
}
可以通过修改name
和maxCount
来修改上传name
和设置上传的文件数量
。
添加额外参数
只需要在FileFieldsInterceptor
方法的数组参数中扩充即可。
这样我们上传文件的Controller
就已经实现了。
Service实现
在实现Controller
时,我们事先定义了UploadService
,现在就来实现这个Service
。Service
的骨架我就不写了,这里主要是来实现uploadService.uploadLocal
方法。
import * as fs from "fs";
//...
async uploadLocal(request) {
const file = request.file[0];
try {
fs.readdirSync(`./public/uploads`);
} catch (err) {
fs.mkdirSync(`./public/uploads`);
}
const now = this.Moment().format("YYYYMMDD");
try {
fs.readdirSync(`./public/uploads/${now}`);
} catch (err) {
fs.mkdirSync(`./public/uploads/${now}`);
}
fs.writeFileSync(
`./public/uploads/${now}/${file.originalname}`,
file.buffer,
);
// 数据返回
return {
code:0,
data:{
fileUrl: `uploads/${now}/${file.originalname}`,
}
}
}
接下来介绍一下上述代码实现了什么?
- 引入
fs模块
用来读写文件 - 因为我这里只上传一个文件,所以读取
request.file[0]
拿到第一个文件 - 尝试读取
public
下是否有uploads
目录,如果没有则创建 - 定义当日的时间并格式化为
YYYYMMDD
- 尝试读取
public/uploads
下是否有当日
的目录,如果没有则创建 - 将文件写入到当日的目录中
- 将本地路径返回
最终存放的路径如:public/uploads/20230416/demo.png
到此为止,一个简易的文件上传就实现了。
结语
我是一名前端程序员,但不止于前端,如果文章哪里写的有些欠妥,欢迎评论指正,大家一起学习,一起进步~