1. 程式人生 > >express中用mongoose操作資料庫-儲存圖片、修改資料(四)

express中用mongoose操作資料庫-儲存圖片、修改資料(四)

從專案的角度上來說,圖片儲存和資料庫儲存都是必須要分離的,否則這一個模組就能拖垮你的整個工程。 二進位制的儲存方式,已經淘汰了,效能非常差,在以後的資料庫版本里已經取消了這個儲存方式。存放路徑,是一種非常方便的解決方案,不存在什麼其他的問題,容易管理。比如,你以前用二進位制儲存的一個圖片,又要IO又要快取的才能展示給使用者看。現在你儲存的是地址,僅僅需要把連結提取出來即可,這樣減少了資料訪問上的壓力。
所以要先將圖片檔案上傳到伺服器,,再往資料庫中存圖片檔案的路徑,怎麼傳二進位制檔案呢?form表單可以,但是不是非同步的,ajax是非同步的,但是要xhr2才支援傳二進位制檔案,所以這裡用H5支援的一個物件FormData,相當於模擬一個表單提交將圖片傳至伺服器,當然還是要用到一個外掛,formidable,具體流程:
a:cnpm i --save formidable 安裝外掛,安裝好後,它還需要一個配置模組:
var cacheFolder = 'uploadcache/';//存放圖片的檔名稱
exports.upload = function(req, res) {
    var fs = require('fs');
    var formidable = require('formidable');
    //var currentUser = req.session.username; // 
    var userDirPath =cacheFolder /*+ currentUser;*/
    if (!fs.existsSync(userDirPath)) {
        fs.mkdirSync(userDirPath);
    }
    var form = new formidable.IncomingForm(); //建立上傳表單
    form.encoding = 'utf-8'; //設定編輯
    form.uploadDir = userDirPath; //設定上傳目錄
    form.keepExtensions = true; //保留後綴
    form.maxFieldsSize = 2 * 1024 * 1024; //檔案大小
    form.type = true;
    var displayUrl;
    form.parse(req, function(err, fields, files) {
        if (err) {
            res.send(err);
            return;
        }
        var extName = ''; //字尾名
        switch (files.upload.type) {
            case 'image/pjpeg':
                extName = 'jpg';
                break;
            case 'image/jpeg':
                extName = 'jpg';
                break;
            case 'image/png':
                extName = 'png';
                break;
            case 'image/x-png':
                extName = 'png';
                break;
        }
        if (extName.length === 0) {
            res.send({
                code: 202,
                msg: '只支援png和jpg格式圖片'
            });
            return;
        } else {
            var avatarName = '/' + Date.now() + '.' + extName;
            var newPath = form.uploadDir + avatarName;
            displayUrl = /*currentUser +*/ avatarName;
            fs.renameSync(files.upload.path, newPath); //重新命名
            res.json({
                code: 0,
                img: displayUrl
            });
        }
    });
};
b,前端往伺服器儲存:
//圖片上傳
	var $imgFile = $(".submit .img input[type=file]");
	$imgFile.change(function(){
		var type = this.files[0].type;
		if(type === "image/png" || type === "image/jpeg"){
			var form = new FormData();//H5的物件
			form.append("upload", this.files[0]);//第一個引數代表封裝的這個物件的key,跟後臺協商;
			//非同步上傳圖片物件
			$.ajax({
				url: "/upload",
				type: "POST",
				dataType:"json",
				data: form,
				contentType: false, //傳送資訊到伺服器的內容型別 告訴jq不要去設定Content-Type請求頭,預設是 application/x-www-form-urlencoded (form型別) 
		        processData: false, //processData 是jq 獨有的引數 用於對data引數進行序列化處理,預設值是true,
		                     //所謂序列化 就是比如{ width:1680, height:1050 }引數物件序列化為width=1680&height=1050這樣的字串。
			}).done(function(res){
				if(!res.code){
					$("#img").attr("src", res.img);//顯示預覽圖,到時往資料庫儲存圖片路徑時就在這個圖片上獲取就可以了
				}

			})
		}
	})
c.前端上傳完圖片,填寫完評論內容後提交評論(將圖片路徑,評論詳情儲存到資料庫),並且收到了後端返回的提交的資料,再次呼叫模板引擎往html中append這條評論:
//評論提交
	var $tit = $("#tit"), $con = $("#con"), $img = $("#img"), $sbt = $("#sbt");
	$sbt.click(function(){
		var params = {
			title: $tit.val(),
			content: $con.val(),
			img: $img.attr("src"),
			author: u
		};
		if(!params.title || !params.content){
			alert("不能為空!");
			return;
		};
		$.post("/sbtComment", params, function(data){
			if(!data.code){
				if($("h2.empty").is(":visible")){
					$("h2.empty").hide();
				}
				var html = template("commentList", data);
				$list.append(html);
				$tit.val("");
				$con.val("");
				$img.attr("src", "");
			}
		})
	})
這是後端的處理:
//評論提交
app.post("/sbtComment", function(req, res){
	var comment = new Comment(req.body);
	comment.save(function(err, doc){//這個doc就是儲存的物件
		if(err){return};
		res.json({
			code: 0,
			list: [doc]
		})
	})
})
d.修改評論,前端類似的操作:
//評論修改
	var $xtit = $("#xtit"), $xcon = $("#xcon"), $ximg = $("#ximg"), $xsave = $("#xsave");
	$list.on("click", ".btn-warning", function(){//點選修改彈出模態框同時獲取原內容
		$xsave.data("id", $(this).data("id"));//將點選的這條評論的id用自定義屬性儲存到模態框確認按鈕上
		$xtit.val($(this).parent().prev(".col-md-10").children("h4").text());
		$xcon.val($(this).parent().prev(".col-md-10").children("p").text());
		$ximg.attr("src", $(this).parent().prev(".col-md-10").find("img").attr("src"));
	})
	$(".modal-body .ximg input[type=file]").change(function(){//修改圖片
		var type = this.files[0].type;
		if(type === "image/png" || type === "image/jpeg"){
			var form = new FormData();//H5的物件
			form.append("upload", this.files[0]);//第一個引數代表封裝的這個物件的key,跟後臺協商;
			//非同步上傳圖片物件
			$.ajax({
				url: "/upload",
				type: "POST",
				dataType:"json",
				data: form,
				contentType: false, //傳送資訊到伺服器的內容型別 告訴jq不要去設定Content-Type請求頭,預設是 application/x-www-form-urlencoded (form型別) 
		        processData: false, //processData 是jq 獨有的引數 用於對data引數進行序列化處理,預設值是true,
		                     //所謂序列化 就是比如{ width:1680, height:1050 }引數物件序列化為width=1680&height=1050這樣的字串。
			}).done(function(res){
				if(!res.code){
					$ximg.attr("src", res.img);
				}

			})
		}
	})
	$xsave.click(function(){//儲存修改
		var params = {
			title: $xtit.val(),
			content: $xcon.val(),
			img: $ximg.attr("src"),
			_id: $(this).data("id")
		};
		if(!params.title || !params.content){
			alert("不能為空!");
			return;
		};
		$.post("/modifyComment", params, (data)=>{
			if(!data.code){
				var html = template("commentList", data);
				$(".list-group").find("input[data-id="+$(this).data("id")+"]").parents(".list-group").replaceWith(html);
				$('#myModal').modal('hide');//關閉模態框
			}
		});
	})
後端的處理:
//評論修改
app.post("/modifyComment", function(req, res){
	let {_id, title, content, img} = req.body;
					//引數3:new取布林值,true表示返回修改的這個物件,
	Comment.findOneAndUpdate({_id}, {title, content, img}, {new: true}, function(err, doc){
		if(err){return};
		res.json({
			code: 0,
			list: [doc]
		})
	})
})

到這裡利用前端開發框架express結合mongoose對mongodb資料庫的增刪改查已經熟悉了