//生成multiparty對象,並配置上傳目標路徑
var form = new multiparty.Form({uploadDir: (mainPath + '/picTemp/')});
我們生成multiparty對象後,就可以使用multiparty.from().parse(req, callback)進行文件上傳。文件上傳成功實際上就會上傳到我們剛纔定義的上傳目錄中,然後返回files。我們可以看下文件上傳效果:
//查看圖片是否超過限制
var picNum = 0;
par.picNames = Object.keys(files);
var picSizeArr = [];
for(var picKey in files){
if(files[picKey].length > 1){//每個名字只能帶一張圖片
delPicsWithFiles(files);
return cb('文件參數有誤', 400);
}
par[picKey] = files[picKey][0].path;
picNum += files[picKey].length;
picSizeArr.push(parseInt(files[picKey][0].size));
}
//根據上傳來的files表單刪除圖片
function delPicsWithFiles(files) {
//圖片超過限制,刪除上傳來的圖片
for (var key in files) {
files[key].forEach(function (picObj) {
var uploadedPath = picObj.path;
fs.unlink(uploadedPath, function () {
});
});
}
}
第一步校驗通過了,下一步就是針對圖片和非圖片做不同的操作。圖片允許多圖同時上傳,所以我們需要判斷上傳的圖片是否超過我們限制的最大張數,如果圖片張數超限,則刪除所有已上傳圖片:
if(picNum > maxPic){
//圖片超過限制,刪除上傳來的圖片
delPicsWithFiles(files);
return cb('圖片個數超過限制', 400);
}
並且需要判斷圖片文件大小是否符合規範,一般大小要和服務器配置一致,防止文件大小超過服務器限制大小。
if(picSizeArr[0] > 4000000) {
delPicsWithFiles(files);
return cb('圖片過大,請重新選圖!',400);
}
//檢驗參數是否正確,包括圖片命名,不正確的話去刪除上傳的圖片,並且返回錯誤
checkParFunc(par,function (err,errCode) {
if(!err){//驗證正確,去重命名
par.files = files;
picHelp.renamePics(par,pathDir,isNeedUid,function (err,errCode,param) {
if(err){
cb(err, errCode, param);
delPicsWithFiles(files);
return;
}
cb(null, 0, param);
});
return;
}
//驗證不正確,刪除上傳來的圖片
delPicsWithFiles(files);
cb(err,errCode);
});
function checkParFunc(par, cb) {
if (!par.banner1 || !par.shopTitle1 || !par.price1 || !par.score1 || !par.linkUrl1) {
return cb('參數不全', 400);
}
cb(null, 0, par);
}
如果到這裏檢驗通過一般來說我們圖片上傳業務邏輯沒問題了。但是我們還是可以繼續優化,剛纔上傳成功的截圖我們可以看到文件上傳後文件名都是隨機字符串,我們很多時候都是需要對文件上傳做分類纔可以維護數據。所以下一步我們通過分割時間戳按照時間來將上傳的圖片轉移到新的文件夾存儲,並且我們移動到真正存儲的文件夾時,通過fs.readFile()取到文件後綴名,然後將文件重命名成按時間戳進行命名,最終移動文件夾返回文件所在的地址,文件上傳邏輯大功告成:
//給上傳的圖片重命名 //par:參數 picType:路徑名
picHelp.renamePics = function (par,picType,isNeedUid,cb) {
if(!par.files){
cb('參數有誤',400);
return;
}
//構造路徑
var uid = 0;
if(par.userInfo){
uid = par.userInfo.main_userInfo ? par.userInfo.main_userInfo.uid : par.userInfo.uid;
}
var date = new Date();
var userPath = '/' + picType;
userPath += '/' + date.getFullYear();
userPath += '/' + (date.getMonth()+1);
userPath += '/' + date.getDate();
if(isNeedUid == true) {
userPath += '/' + parseInt(uid / 100);
userPath += '/' + uid;
}
mkdirs((mainPath + userPath),function (err) {//創建目錄
if(err){
cb(err,400);
return;
}
userPath += '/' + date.getHours() + date.getMinutes() + date.getSeconds() + date.getMilliseconds();
changeDir(par, 0, userPath, function (err, par) {
if (err) {
cb(err, 400,par);
return;
}
cb(null, 0, par);
});
});
}
//遞歸創建目錄 異步方法
function mkdirs(dirname, callback) {
fs.exists(dirname, function (exists) {
if (exists) {
callback(null);
} else {
mkdirs(path.dirname(dirname), function () {
fs.mkdir(dirname, callback);
});
}
});
}
//更新圖片路徑
function changeDir(par,index,userPath,callback) {
var keyArr = Object.keys(par.files);
if(keyArr.length < 1){
callback(null,par);
return;
}
var picObj = par.files[keyArr[index]][0];
var uploadedPath = picObj.path;
fs.readFile(uploadedPath, function (err,bytesRead) {
if (err) {
callback(err,par);
return;
}
var info = imageInfo(bytesRead);
var type;
if(!info || !info.format){
type = '.jpg';
}else {
type = imageInfoFileType(info.format);
if (!type) {
callback('上傳圖片格式有誤', par);
return;
}
}
//參數正確 更換圖片路徑
var picPach = userPath + type;
var dstPath = mainPath + picPach;
checkDirs(dstPath,function (exits) {
if(exits){
picPach = userPath + (keyArr.length + index) + type;
dstPath = mainPath + picPach;
}
//重命名爲真實文件名
fs.rename(uploadedPath,dstPath,function (err) {
if(err){
callback(err,par);
return;
}
par[picObj.fieldName] = picPach;
if(index < (keyArr.length-1)){
changeDir(par,index+1,userPath,callback);
}else {
callback(null,par);
}
});
});
});
}
if(par.mp4_url) {
if(!files.mp4_url || !files.mp4_url[0] || !files.mp4_url[0].size || files.mp4_url[0].size == 0) {
cb('視頻上傳時發生錯誤!', 400);
return;
}
if(files.mp4_url[0].size > 8000000) {
fs.unlink(par.mp4_url, function () {});
cb('文件文件過大',400);
return;
}
delete files['mp4_url'];
delPicsWithFiles(files);
pathDir = 'bbs_mp4';
checkParFunc(par, function (err,errCode) {
if(err){
fs.unlink(par.mp4_url, function () {});
return cb(err, errCode);
}
picHelp.renameVideo(par,pathDir,isNeedUid,function (err,errCode,param) {
if(err){
cb(err,errCode,param);
fs.unlink(par.mp4_url, function () {});
return;
}
cb(null, 0, param);
});
return;
});
}
//文件上傳
picHelp.renameVideo = function (par,picType,isNeedUid,cb) {
var uid = 0;
if(par.userInfo){
uid = par.userInfo.main_userInfo ? par.userInfo.main_userInfo.uid : par.userInfo.uid;
}
var date = new Date();
var userPath = '/' + picType;
userPath += '/' + date.getFullYear();
userPath += '/' + (date.getMonth()+1);
userPath += '/' + date.getDate();
if(isNeedUid == true) {
userPath += '/' + parseInt(uid / 100);
userPath += '/' + uid;
}
mkdirs((mainPath + userPath),function (err) {//創建目錄
if(err){
cb(err,400);
return;
}
userPath += '/' + date.getHours() + date.getMinutes() + date.getSeconds() + date.getMilliseconds();
var uploadedPath = par.mp4_url;
fs.readFile(uploadedPath, function (err) {
if (err) {
cb(err, 400);
return;
}
var type = par.mp4_url.split('.')[1];
var picPach = userPath + '.' + type;
par.mp4_name = picPach;
var dstPath = mainPath + picPach;
checkDirs(dstPath,function (exits) {
if(exits){
picPach = userPath + type;
dstPath = mainPath + picPach;
}
fs.rename(uploadedPath,dstPath,function (err) {
if(err){
cb(err,400);
return;
}
par.mp4_url = par.mp4_name;
cb(null, 0, par);
});
});
});
});
}
https://gitee.com/mqzuimeng_admin/wx_blog.git
本文分享自微信公衆號 - 程序猿周先森(zhanyue_org)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。