批量上传文件¶
需求分析¶
很多用户需要一次性上传多篇小说,如果每次只上传一篇太麻烦,所以支持用户本地上传 txt md 等格式文件到服务器,并统一保存到数据库。
前端发送数据¶
在已有单文件上传的基础上,更改 input 属性,支持多选文件
<input
className="local-file-input"
type="file"
accept={INPUT_ACCEPT_FILE_TYPE}
onChange={this.onFileChange}
multiple
></input>
创建一个函数来处理文件上传
onFileChange = (event) => {
const files = Array.from(event.target.files);
// 需要把多文件循环加入到 formData 中上传
const formData = new FormData();
files.forEach(file => {
formData.append('files', file);
});
axios.post(`${setting.server}/api/batch-upload-novel`, formData, {
headers: {
// 请求内容是一个多部分的表单数据,通常用于上传文件,因为文件需要被编码成多部分的形式发送到服务器。
'Content-Type': 'multipart/form-data'
}
});
};
后端接收数据¶
获取 POST 请求中的 formData 数据,可以使用 multer 中间件
在 api 中增加对应的路由,并使用 multer 处理上传文件
const express = require('express');
const multer = require('multer');
const app = express();
// upload.none() 表示不处理文件上传,只处理表单数据
// upload.single('file') 表示处理一个名为 file 的文件字段
// upload.array('files', 10) 表示允许上传最多 10 个文件,文件字段名称为 files
router.post("/batch-upload-novel", upload.array('files', 10), ApiNovel.batchUploadNovel);
在回调函数中,获取文件,对信息进行格式化,然后一个 SQL 语句写入数据库:
static batchUploadNovel(req, res) {
const files = req.files;
try {
const fileContents = files.map(file => file.buffer.toString('utf8'));
const fileNames = files.map(file => {
if (file.encoding === 'utf-8') {
return file.originalname;
}
// 格式 7bit 编码格式是 ASCII 编码格式的一个子集,用于表示 ASCII 字符集中的字符,需要 'latin1'转换
else if (file.encoding === '7bit') {
return Buffer.from(file.originalname, 'latin1').toString('utf8');
}
else if (file.encoding === 'binary') {
return Buffer.from(file.originalname, 'binary').toString('utf8');
}
else if (file.encoding === 'gbk' || file.encoding === 'gb2312') {
return Buffer.from(file.originalname, file.encoding).toString('utf8');
}
});
const cover_photo = "https://www.baidu.com/img/flexible/logo/pc/result@2.png"; // use default book image
const author = "佚名";
const price = 0;
const size = 1;
const tag = "";
const briefs = fileContents.map(item => item.slice(0, 300));
// 在 MariaDB 中,你可以使用以下方法来插入多条数据:使用单个 INSERT INTO 语句,多个 VALUES 子句:
// INSERT INTO book (name, cover_photo, author, detail, price, brief, size, tag) VALUES (), ()
let sql = 'INSERT INTO book (name, cover_photo, author, detail, price, brief, size, tag) VALUES';
let data = [];
for (let i = 0; i < fileNames.length; i++) {
if (i === fileNames.length - 1) {
sql += `(?, ?, ?, ?, ?, ?, ?, ?);`;
} else {
sql += `(?, ?, ?, ?, ?, ?, ?, ?),`;
}
data.push(fileNames[i], cover_photo, author, fileContents[i], price, briefs[i], size, tag);
}
DBHelper(sql, (err, results) => {
if (err) {
logger.error(err);
res.status(400).send({ error_massage: err });
return;
}
res.status(200).send("success");
}, data);
} catch (error) {
logger.error(error);
res.status(400).send({ error_massage: 'File upload failed, coding is not supported, please try again' });
}
}