React使用Multer和Express.js单个文件上传
当我们想要添加上传或删除文件的功能时,文件存储变得至关重要,无论是用于网站还是个人用途。使用Express的文件存储项目旨在开发一个网络应用程序,为用户提供安全高效的在线文件存储和管理方式。通过Express,我们将能够创建一个用户友好的应用程序,轻松上传、删除和显示文件。让我们开始这个令人兴奋的项目吧!
最终输出的预览:
先决条件和技术:
- Express:Express将被用于构建整个文件存储的后端。
- Multer:Multer模块将被用于上传文件。
- Ejs:EJS将被用于渲染HTML页面。
- Bootstrap:Bootstrap将被用于优雅的页面设计和展示。
方法:
我们将利用Express来开发整个后端,Multer模块将被用于文件上传。应用程序将包括三个路由:上传、删除和查看。上传路由将用于文件上传,删除路由将用于删除特定文件,查看路由将用于显示所有文件。HTML页面将用于显示所有文件,以及上传和删除的选项。文件将存储在服务器的/file storage文件夹中,应用程序将支持所有类型的文件。
功能:
- 文件上传: 此选项允许用户从计算机上传文件到服务器。
- 文件删除: 此选项删除服务器上存储的选定文件,如果文件未找到,则会抛出错误。
- 查看所有文件: 此选项在HTML页面上显示从服务器上传的所有文件。可以点击链接查看文件。
创建项目的步骤:
步骤1: 首先,我们需要使用以下命令创建React应用程序
npx create-react-app <<Project_Name>>
步骤2: 导航到文件夹
cd <<Project_Name>>
步骤3 : 使用下面的命令安装以下软件包。
npm install express multer ejs
步骤4: 现在在项目文件夹中创建app.js文件。我们首先设置express应用程序创建express app实例。配置app使用EJS。对于EJS,在项目文件夹内创建/views文件夹。这个文件夹将包含我们的HTML代码。
项目结构:
package.json 中的 更新的依赖项 将会如下所示:
{
"name": "gfg-filestorage",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node app.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.9",
"express": "^4.18.2",
"multer": "^1.4.5-lts.1"
}
}
示例:
- App.js: 这是主服务器文件,我们将在此定义所有路由并启动服务器以监听端口3000。
- index.ejs: 此文件将包含我们正在制作的项目的视图或模板设计,我们正在使用EJS作为视图引擎。
// app.js
const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
const app = express();
const port = 3000;
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'filestorage/');
},
filename: (req, file, cb) => {
const fileName = `{Date.now()}-{file.originalname}`;
cb(null, fileName);
},
});
const upload = multer({ storage });
app.use('/uploads', express.static(path.join(__dirname, 'filestorage')));
app.get('/', (req, res) => {
res.render('index')
});
app.post('/upload', upload.single('file'), (req, res) => {
res.redirect('/')
});
app.delete('/delete/:fileName', (req, res) => {
const fileName = req.params.fileName;
const filePath = path.join(__dirname, 'filestorage', fileName);
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
res.send(`File "{fileName}" has been deleted.`);
} else {
res.status(404).send(`File "{fileName}" not found.`);
}
});
app.get('/view', (req, res) => {
const uploadDirectory = path.join(__dirname, 'filestorage');
fs.readdir(uploadDirectory, (err, files) => {
if (err) {
console.error(err);
res.status(500).send('Error reading the upload directory.');
} else {
res.json({ files });
}
});
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
Javascript代码
// index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0">
<title>File Storage App</title>
<script src=
"https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.9.4/umd/popper.min.js">
</script>
<script src=
"https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.min.js">
</script>
<link href=
"https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css"
rel="stylesheet">
<link href=
"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.3.0/css/all.min.css"
rel="stylesheet">
</head>
<body>
<div class="container">
<h1 class="mt-5 text-success">GeeksForGeeks File Storage</h1>
<h2 class="mt-4">Upload File</h2>
<form action="/upload" method="POST"
enctype="multipart/form-data">
<div class="mb-3">
<input type="file" name="file"
class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Upload</button>
</form>
<h2 class="mt-4">Delete File</h2>
<form id="deleteForm">
<div class="mb-3">
<select id="fileSelect" name="fileName"
class="form-select">
</select>
</div>
<button type="button" class="btn btn-danger"
onclick="deleteFile()">Delete</button>
</form>
<h2 class="mt-4">Uploaded Files</h2>
<ul id="fileList" class="list-group">
</ul>
</div>
<script>
function populateFileListWithIcons() {
fetch('/view')
.then(response => response.json())
.then(data => {
const fileList = document.getElementById('fileList');
fileList.innerHTML = '';
data.files.forEach(fileName => {
const listItem = document.createElement('li');
listItem.className = 'list-group-item d-flex justify-content-between align-items-center';
const fileExtension = fileName.split('.').pop();
const iconSpan = document.createElement('span');
iconSpan.className = 'me-3';
iconSpan.innerHTML = getFileIconHTML(fileExtension);
const fileLink = document.createElement('a');
fileLink.href = `/uploads/{fileName}`;
fileLink.textContent = fileName;
listItem.appendChild(iconSpan);
listItem.appendChild(fileLink);
fileList.appendChild(listItem);
});
})
.catch(error => console.error(error));
}
function getFileIconHTML(fileExtension) {
const iconClasses = {
pdf: 'far fa-file-pdf',
doc: 'far fa-file-word',
docx: 'far fa-file-word',
xls: 'far fa-file-excel',
xlsx: 'far fa-file-excel',
ppt: 'far fa-file-powerpoint',
pptx: 'far fa-file-powerpoint',
txt: 'far fa-file-alt',
jpg: 'far fa-file-image',
jpeg: 'far fa-file-image',
png: 'far fa-file-image',
gif: 'far fa-file-image',
default: 'far fa-file'
};
return `<i class="{iconClasses[fileExtension.toLowerCase()] || iconClasses['default']}">
</i>`;
}
function deleteFile() {
const deleteForm = document.getElementById('deleteForm');
const formData = new FormData(deleteForm);
fetch(`/delete/${formData.get('fileName')}`, {
method: 'DELETE',
})
.then(response => response.text())
.then(message => {
alert(message);
populateFileListWithIcons();
populateDeleteOptions();
})
.catch(error => console.error(error));
}
function populateDeleteOptions() {
fetch('/view')
.then(response => response.json())
.then(data => {
const fileSelect = document.getElementById('fileSelect');
fileSelect.innerHTML = '';
data.files.forEach(fileName => {
const option = document.createElement('option');
option.value = fileName;
option.textContent = fileName;
fileSelect.appendChild(option);
});
})
.catch(error => console.error(error));
}
populateFileListWithIcons();
populateDeleteOptions();
</script>
</body>
</html>
运行应用程序的步骤:
第 1 步 在终端中输入以下命令。
npm start
第 2 步 打开网页浏览器并输入以下URL
http://localhost:3000/
输出:
是一个用于创建和维护Web页面的标记语言。它由一系列的元素(标签)组成,这些标签有不同的功能和用途,例如标记文本、插入图像、添加链接等。HTML使用尖括号(<>)将标签括起来,并使用属性为标签提供更多的信息。在浏览器中,HTML会被解析并显示为可视化的Web页面。