Nest 使用 ssh2-sftp-client
安装
bash
npm install --save ssh2-sftp-client配置文件
ts
# 开发环境配置
app:
prefix: ''
port: 8080
logger:
# 项目日志存储路径,相对路径(相对本项目根目录)或绝对路径
dir: '../logs'
# 文件相关
file:
# 是否为本地文件服务或cos
isLocal: true
# location 文件上传后存储目录,相对路径(相对本项目根目录)或绝对路径
location: '../upload'
# 文件服务器地址,这是开发环境的配置 生产环境请自行配置成可访问域名
domain: 'http://localhost:8080'
# 文件虚拟路径, 必须以 / 开头, 如 http://localhost:8080/profile/****.jpg , 如果不需要则 设置 ''
serveRoot: '/profile'
# 文件大小限制,单位M
maxSize: 10
# 腾讯云cos配置
cos:
secretId: ''
secretKey: ''
bucket: ''
region: ''
domain: ''
location: ''
# 数据库配置
db:
mysql:
host: 'xxxxx'
username: 'root'
password: 'xxxxx'
database: 'prismalianbiao'
port: 3306
charset: 'utf8mb4'
logger: 'file'
logging: true
multipleStatements: true
dropSchema: false
synchronize: true
supportBigNumbers: true
bigNumberStrings: true
mysqlread:
host: 'xxxxx'
username: 'root'
password: 'xxxxx'
database: 'prismalianbiao2'
port: 3306
charset: 'utf8mb4'
logger: 'file'
logging: true
multipleStatements: true
dropSchema: false
synchronize: true
supportBigNumbers: true
bigNumberStrings: true
# redis 配置 过期时间1 小时
redis:
host: 'xxxxx'
password: 'redis_n6BSFa'
port: 6379
db: 0
keyPrefix: ''
ttl: 3600
# jwt 配置
jwt:
secretKey: 'jsopy'
expiresin: '1h'
refreshExpiresIn: '2h'
# 权限 白名单配置
perm:
router:
whiteList: [
{ path: '/users/config', method: 'GET' },
{ path: '/users/register/jwt', method: 'POST' },
# { path: '/users/login/jwt', method: 'POST' }, 这里我取消了 因为我默认就是jwt登录
{ path: '/users/login/custom', method: 'POST' },
{ path: '/users/login/basic', method: 'POST' },
{ path: '/users/check/ftp', method: 'POST' },
{ path: '/users/upload/ftp', method: 'POST' },
{ path: '/users/mkdir/ftp', method: 'POST' },
{ path: '/users/deldir/ftp', method: 'POST' },
{ path: '/users/delfile/ftp', method: 'POST' },
]
# 拦截器白名单
noglobalinterceptor:
router:
whiteList: []
# 用户相关
# 初始密码, 重置密码
user:
initialPassword: '123456'
# 自己写的测试
testconfig:
test: 'dev'
# FTP 配置
ftp:
host: 'xxxxx'
port: 22
userName: 'xxxx'
passWord: 'xxxxxx'
root: '/xxx/xx/xx/x'使用
- 创建 ftp 模块 和 ftp.service.ts
ftp.module.ts
bash
import { Module } from '@nestjs/common';
import { FtpService } from './ftp.service';
@Module({
providers: [FtpService],
exports: [FtpService],
})
export class FtpModule {}ftp.service.ts
ts
import { Injectable } from "@nestjs/common";
import SftpClient from "ssh2-sftp-client";
import { ConfigService } from "@nestjs/config";
@Injectable()
export class FtpService {
constructor(private readonly configService: ConfigService) {}
// FTP 初始化
async init() {
const client = new SftpClient();
try {
await client.connect({
host: this.configService.get("ftp").host,
user: this.configService.get("ftp").userName,
password: this.configService.get("ftp").passWord,
secure: true,
});
console.log("ftp连接成功");
return client;
} catch (error) {
console.log(error);
return false;
}
}
// 列出目录
async getList() {
let client: any = null;
try {
client = await this.init();
// 列出目录内容
const dir = this.configService.get("ftp").root;
const files = await client.list(dir);
console.log(`${dir} 目录内容:`, files);
} catch (error) {
console.log(error);
throw new Error(error);
} finally {
// 关闭连接
await client.end();
}
}
// 创建目录
async mkdirftp(moduleName) {
let client: any = null;
try {
client = await this.init();
// 创建目录
const dir = this.configService.get("ftp").root;
// 获取年份
const year = new Date().getFullYear();
// 获取月份
const month = new Date().getMonth() + 1;
// 月份前面补0
const formattedMonth = month.toString().padStart(2, "0");
// 获取日期
const day = new Date().getDate();
// 日期前面补0
const formattedDay = day.toString().padStart(2, "0");
const customdir = `${dir}/${moduleName}/${year}/${formattedMonth}/${formattedDay}/`;
// 判断目录是否存在 d 就是已经存在 false 就是不存在
const hasdir = await client.exists(customdir);
console.log("hasdir");
console.log(hasdir);
if (hasdir) {
console.log(`目录 ${customdir} 已存在`);
return {
status: false,
url: `${customdir}`,
};
} else {
await client.mkdir(customdir, true);
console.log(`已创建目录 ${dir}`);
return {
status: true,
url: `${customdir}`,
};
}
} catch (error) {
console.log(error);
} finally {
// 关闭连接
await client.end();
}
}
// 删除目录
async deldirftp(path) {
let client: any = null;
try {
client = await this.init();
// 判断目录是否存在
const dir = this.configService.get("ftp").root;
// 存在就是d 不存在就是false
const hasdir = await client.exists(`${dir}/${path}`);
console.log("hasdir");
console.log(hasdir);
if (hasdir) {
console.log(`目录存在`);
await client.rmdir(`${dir}/${path}`, true);
return true;
} else {
return false;
}
} catch (error) {
console.log(error);
} finally {
// 关闭连接
await client.end();
}
}
// 上传文件起名
/**
* 生成一个唯一的文件名
* @param {string} extension - 文件扩展名(可选)
* @returns {Promise<string>} 返回生成的唯一文件名
*/
async generateUniqueFileName(extension) {
// 获取当前时间戳
const timestamp = new Date().getTime();
// 生成一个0到99999999之间的随机数
const random = Math.floor(Math.random() * 100000000);
// 组合时间戳和随机数,并添加文件扩展名(如果提供)
const fileName = `${timestamp}_${random}${
extension ? "." + extension : ""
}`;
// 返回生成的唯一文件名
return fileName;
}
// 上传文件
async uploadfile(moduleName) {
let client: any = null;
try {
client = await this.init();
// 先创建目录
const resultUrl: { status: boolean; url: string } | undefined =
await this.mkdirftp(moduleName);
if (!resultUrl) {
return false;
} else {
// 我这里拿本地路径举例子
const localFile = process.cwd() + "/public/ReadMe.txt";
const fileName = await this.generateUniqueFileName("txt");
const remoteFile = resultUrl.url + fileName;
await client.put(localFile, remoteFile);
return true;
}
} catch (error) {
console.log(error);
throw new Error(error);
} finally {
// 关闭连接
await client.end();
}
}
// 删除文件
async delfile(path) {
let client: any = null;
try {
client = await this.init();
// 判断文件是否存在
const dir = this.configService.get("ftp").root;
// 存在就是d 不存在就是false
const hasdir = await client.exists(`${dir}/${path}`);
if (hasdir) {
await client.delete(`${dir}/${path}`);
return true;
} else {
return false;
}
} catch (error) {
console.log(error);
}
}
}使用
- 我这里就在 user 模块里使用
user.module.ts
ts
import { Module } from "@nestjs/common";
import { UsersService } from "./users.service";
import { UsersController } from "./users.controller";
import { FtpModule } from "../ftp/ftp.module";
@Module({
imports: [FtpModule],
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}users.controller.ts
ts
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
Req,
UseGuards,
} from "@nestjs/common";
import { UsersService } from "./users.service";
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get("config")
async getconfig() {
return this.usersService.getConfig();
}
// 获取目录
@Post("check/ftp")
async checkftp(@Req() req: any) {
const result = await this.usersService.checkftp();
return {
data: result,
};
}
// 创造目录
@Post("mkdir/ftp")
async mkdir(@Body() body: any) {
// body.module 就是模块名
const result = await this.usersService.mkdirftp(body.module);
return {
data: result,
code: 200,
};
}
// 删除目录
@Post("deldir/ftp")
async deldir(@Body() body: any) {
// body.module 就是模块名
const result = await this.usersService.deldirftp(body.path);
return {
data: result,
};
}
// 删除文件
@Post("delfile/ftp")
async delfile(@Body() body: any) {
// body.module 就是模块名
const result = await this.usersService.delfile(body.path);
return {
data: result,
};
}
// 上传FTP
@Post("upload/ftp")
async uploadftp(@Req() req: any) {
const result = await this.usersService.uploadftp(req.body.module);
return {
data: result,
};
}
}users.service.ts
ts
import { Inject, Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { FtpService } from "../ftp/ftp.service";
@Injectable()
export class UsersService {
@Inject()
private readonly configService: ConfigService;
@Inject()
private readonly ftpService: FtpService;
getConfig() {
return this.configService.get("db");
}
// 获取ftp列表
async checkftp() {
await this.ftpService.getList();
}
// 上传文件
async uploadftp(moduleName) {
const result: any = await this.ftpService.uploadfile(moduleName);
if (result) {
return "upload success";
} else {
return "upload fail";
}
}
// 制造目录
async mkdirftp(moduleName) {
const result: any = await this.ftpService.mkdirftp(moduleName);
if (result.status) {
return "目录创建成功";
} else {
return "目录已经存在";
}
}
// 删除目录
async deldirftp(path) {
const result = await this.ftpService.deldirftp(path);
if (result) {
return "目录删除成功";
} else {
return "目录删除失败";
}
}
// 删除文件
async delfile(path) {
const result = await this.ftpService.delfile(path);
if (result) {
return "文件删除成功";
} else {
return "文件删除失败";
}
}
}