我使用express
和admin-bro
及其插件@admin-bro/upload
将上传的图像文件存储在服务器中。
AdminBro
对象使用以下AdminBroOptions
进行初始化
const adminBro = new AdminBro({
resources: [
{
resource: Furniture,
options: {
properties: {
'_id': {
isVisible: { list: false, filter: true, show: true, edit: false }
},
image: {
isVisible: false
}
}
},
features: [uploadFeature({
provider: { local: { bucket: path.join(__dirname, 'public', 'images', 'furniture') } },
properties: {
key: 'image.path',
bucket: 'image.folder',
mimeType: 'image.type',
size: 'image.size',
filename: 'image.filename',
file: 'uploadFile'
}
})]
}
],
branding: {
companyName: "Fran's Furniture"
}
})
文件夹结构:
文件夹结构
我遵循本教程主要针对admin-bro
配置:https://itnext.io/the-easiest-and-fastest-way-to-upload-files-in-node-js-4b49e0123190
我还在server.js文件中添加了app.use('/public', express.static('public'))
但我在上传图像文件时遇到了这个错误:
(node:153012) ExperimentalWarning: The fs.promises API is experimental
Error: EPERM: operation not permitted, mkdir 'F:'
如果我将bucket属性更改为"public":
provider: { local: { bucket: 'public' } }
弹出以下错误(注意"public"文件夹位于F:/而非F:/项目文件夹的路径:
(node:163580) ExperimentalWarning: The fs.promises API is experimental
Error: EXDEV: cross-device link not permitted, rename 'C:UsersLenovoAppDataLocalTempupload_4ca3c78a0517022a555815196102aee6' -> 'F:public5f98496b31e9d37efe9a25841.jpg'
家具模型(如果需要(:
const Image = new mongoose.Schema({
path: String,
type: String,
size: Number,
folder: String,
filename: String
})
const FurnitureSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
description: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
status: {
type: String,
enum: ['show', 'hide'],
default: 'show',
required: true
},
condition: {
type: String,
enum: ['new', 'used'],
required: true
},
image: Image,
category: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Category'
}
})
所以在我看来,这个问题主要是因为bucket选项的配置不正确。如有任何帮助,我们将不胜感激。
项目路径(如果需要(:F:\Tutorials\Self Projects\frans node
我通过自己编写一个自定义的基本提供程序并手动复制+删除文件来解决这个问题:
import { BaseProvider } from '@admin-bro/upload'
import { ActionContext, UploadedFile } from 'admin-bro'
import { promises, existsSync } from "fs"
import { resolve, dirname } from "path"
export class UploadProvider extends BaseProvider {
assetPath: string
constructor(bucket: string, assetPath: string) {
// it requires bucket as a parameter to properly pass it to other methods
super(bucket)
this.assetPath = assetPath
}
async upload(file: UploadedFile, key: string, context: ActionContext): Promise<any> {
const fullPath = resolve(this.assetPath, key)
const dirPath = dirname(fullPath)
if (!existsSync(dirPath)) {
await promises.mkdir(dirPath, { recursive: true })
}
await promises.copyFile(file.path, fullPath)
await promises.unlink(file.path)
return key
}
async delete(key: string, bucket: string, context: ActionContext): Promise<any> {
const filePath = resolve(this.assetPath, key)
if (existsSync(filePath)) {
await promises.unlink(filePath)
const dirPath = dirname(filePath)
const otherFiles = await promises.readdir(dirPath)
if (otherFiles && otherFiles.length == 0) {
await promises.rmdir(dirPath)
}
}
}
path(key: string, bucket: string, context: ActionContext): Promise<string> | string {
return "/" + bucket
}
}
然后,像这样使用:
// ...
const provider = new UploadProvider("assets", ASSET_PATH)
// ...
features: [
uploadFileFeature({ provider, ... })
]