我希望每个人都一切顺利。在过去的两三天里,我一直在尝试做自己的事情并研究一种方法,但我没有运气。有没有办法让我在用户输入一些信息后创建一个目录并更改到该目录以上传文件?我想做的是将文件上传到一个文件夹,该文件夹将根据用户在 multer 上传文件之前输入的信息命名。如果有其他方法,我愿意接受建议。我的代码如下,我已经上传了我的 React js 代码,以防万一。
节点JS:
const express = require('express');
const router = express.Router();
const db = require('../config/db');
const bcrypt = require('bcrypt');
const saltRounds = 10;
const session = require('express-session');
const bodyParser = require('body-parser');
const app = express();
const SqlDbStore = require('express-mysql-session')(session);
const passport = require('passport');
const cookieParser = require('cookie-parser');
const multer = require('multer');
const path = require('path');
//----------------------------------------- BEGINNING OF PASSPORT MIDDLEWARE AND SETUP ---------------------------------------------------
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(passport.session());
app.use(session({
key: 'session_cookie_name',
secret: 'session_cookie_secret',
store: new SqlDbStore({
host: 'localhost',
port: 3306,
user: 'root',
password: '**************',
database: '**************',
}),
resave: false,
saveUninitialized: false,
cookie:{
maxAge:1000*60*60*24,
secure: false
}
}));
const multerDestination = './routes/Images/';
const storage = multer.diskStorage({
destination: function (req, files, cb) {
cb(null, multerDestination);
},
filename: function (req, files, cb) {
cb(null, Date.now() + '-' + files.originalname );
}
});
const upload = multer({ storage: storage }).array('files');
//----------------------------------------- END OF PASSPORT MIDDLEWARE AND SETUP ---------------------------------------------------
router.post('/properties_upload', (req, res) => {
const address = req.body.addressLine;
const address2 = req.body.addressLine2;
const city = req.body.city;
const state = req.body.state;
const addressZipCode = req.body.addressZipCode;
const mlsID = req.body.mlsID;
const rentalID = Math.floor(Math.random()*90000) + 10000;
var directory;
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
return res.status(500).json(err)
} else if (err) {
return res.status(500).json(err)
}
for (const file of req.files) {
directory = path.dirname(file.path);
}
console.log('File path: ' + directory);
return res.status(200).send(req.files);
});
});
module.exports = router;
React JS:
import React, { useEffect, useState } from 'react';
import './Properties_Upload.css';
import Navbar from '../../../Components/Navbar/Navbar';
import Footer from '../../../Components/Footer/Footer';
import Axios from 'axios';
import { useNavigate } from 'react-router-dom';
export default function Properties_Upload() {
const [addressLine, setAddressLine] = useState('');
const [addressLine2, setAddressLine2] = useState('');
const [addressCity, setAddressCity] = useState('');
const [addressState, setAddressState] = useState('');
const [addressZipCode, setAddressZipCode] = useState('');
const [mlsID, setMLSID] = useState('');
const [selectedFile, setSelectedFile] = useState('');
const [errorMessage, setErrorMessage] = useState('');
const navigate = useNavigate();
const propertyInfoHandler = () => {
const url = 'http://localhost:3001/property/properties_upload';
const data = new FormData()
for (var x = 0; x < selectedFile.length; x++) {
data.append('files', selectedFile[x]);
}
Axios.post(url, data, {
addressLine: addressLine,
addressLine2: addressLine2,
addressCity: addressCity,
addressState: addressState,
addressZipCode: addressZipCode,
mlsID: mlsID
})
.then((response) => {
navigate('/properties');
if (response.data.errorMessage){
setErrorMessage(response.data.message);
}
});
};
return (
<>
<Navbar />
<div className='propertiesUploadBody'>
<h1>Properties Upload</h1>
<div className='propertyInfoFormBody'>
<h1>Property Information</h1>
<p className='addressLine'> *Property address: <input name='addressLine' placeholder='Address' required autoComplete="off" onChange={(e) => setAddressLine(e.target.value)} /> </p>
<p className='addressLine2'> Apartment/Suite/Unit: <input name='addressLine2' placeholder='Apartment/Suite/Unit' autoComplete="off" onChange={(e) => setAddressLine2(e.target.value)} /> </p>
<p className='addressCity'> *Property city: <input name='addressCity' placeholder='City' required autoComplete="off" onChange={(e) => setAddressCity(e.target.value)} /> </p>
<p className='addressState'> *Property state: <input name='addressState' placeholder='State' maxLength={2} required autoComplete="off" onChange={(e) => setAddressState(e.target.value)} /> </p>
<p className='addressZipCode'> *Property zip code: <input type='number' name='addressZipCode' placeholder='Zip Code' required autoComplete="off" onChange={(e) => setAddressZipCode(e.target.value)} /> </p>
<p className='propertyMLSID'> MLS ID: <input type='number' name='propertyMLSID' placeholder='MLS ID' required autoComplete="off" onChange={(e) => setMLSID(e.target.value)} /></p>
</div>
<div className='propertyFileFormBody'>
<h1>Property Image Upload</h1>
<p> Upload Images of the property.</p>
<input className='uploadFiles' type='file' name='file' multiple required onChange={(e) => setSelectedFile(e.target.files)} />
</div>
<h2>{errorMessage}</h2>
<button className='uploadButton' onClick={propertyInfoHandler}>Upload Property</button>
</div>
<Footer />
</>
)
}
您可以在调用
cb
函数中的回调destination
之前执行异步文件系统操作。
const storage = multer.diskStorage({
destination: function (req, files, cb) {
var addressLine = req.body.addressLine;
var multerDestination;
// Decide what multerDestination should be based on addressLine or other user info.
fs.mkdir(multerDestination, function(err) {
if (err && err.code !== "EEXIST") cb(err);
else cb(null, multerDestination);
}
},
filename: ...
});
如果您想评估上传文件旁边的其他表单字段(如
addressLine
),则在构建 FormData
时,它们必须位于文件之前:
const data = new FormData();
data.append('addressLine', addressLine);
...
for (var x = 0; x < selectedFile.length; x++) {
data.append('files', selectedFile[x]);
}
Axios.post(url, data).then(...);
否则,当req.body
函数执行时,
destination
还没有被填充。