Node.js學(xué)習(xí)第四、五天筆記之myAlbums項(xiàng)目實(shí)戰(zhàn)

MVC

  • 指的是:models views controller;
    • models:用于后臺(tái)數(shù)據(jù)的查找幔戏;
    • views:視圖,用于存儲(chǔ)瀏覽器頁(yè)面的文件税课;
    • controller:管理者闲延,控制者;用于二者之間的控制韩玩;

myAlbum項(xiàng)目開(kāi)發(fā)

  • 創(chuàng)建文件夾:命令:mkdir
    • models:提供數(shù)據(jù)垒玲;
    • views:模板文件;
    • controller:控制器找颓;
    • uploads:上傳的文件
    • public:靜態(tài)資源
  • 創(chuàng)建文件:命令:touch ; window命令行中使用type nul>
    • app.js:入口文件合愈,創(chuàng)建服務(wù)器;
  • package.json文件:記錄當(dāng)前項(xiàng)目依賴(lài)击狮;命令npm init -y;
  • 安裝項(xiàng)目模塊框架:命令npm install --save-dev express ejs formidable
  • controller文件夾下創(chuàng)建router.js文件佛析;作為一個(gè)路由的控制器;
    • 知識(shí)點(diǎn):在app.js中引入自定義模塊彪蓬,必須添加相對(duì)路徑寸莫;如:const router=require("./controller/router");
    • 在router.js中設(shè)置代碼輸出參數(shù);
     exports.showIndex=function (req, res) {
         res.render("index")
     };
    
    • 在app.js中直接引入:router.showIndex獲取匿名函數(shù);
  • 靜態(tài)資源文件加載
    • 設(shè)置靜態(tài)資源在public文件下:app.use(express.static("./public"));档冬;即相對(duì)路徑都在public目錄下膘茎;
    • 在ejs文件中,通過(guò)link引入css文件和通過(guò)script引入js文件酷誓;都會(huì)發(fā)送對(duì)應(yīng)的請(qǐng)求披坏;請(qǐng)求地址為href和src中的路徑地址;
    • 在通過(guò)get請(qǐng)求盐数,打開(kāi)index.ejs文件后棒拂,會(huì)在頁(yè)面中繼續(xù)發(fā)送請(qǐng)求;頁(yè)面想要有css樣式和js動(dòng)效娘扩,必須保證css文件和js文件能夠正常引入着茸;如何在頁(yè)面中渲染打開(kāi)css文件壮锻;css的引入地址是很重要的;
    • 代碼:app.use(express.static("./public"));中將靜態(tài)資源的目錄設(shè)置在public目錄下涮阔,即所引入的css文件和js文件必須在此目錄下添加相對(duì)路徑猜绣,然后找到文件才能打開(kāi);
    • 所以敬特,將css文件和js文件放在public文件夾下掰邢,在引入時(shí)添加相對(duì)路徑;如:<link href="/css/bootstrap.css" rel="stylesheet"><script src="/js/bootstrap.js"></script>伟阔;注意:css前斜杠最好添加上辣之,若不添加,會(huì)被拼接在地址的后面皱炉,會(huì)出錯(cuò)怀估,所以必須添加;
    • 在地址欄中輸入地址localhost:8080/css/bootstrap.css也可以打開(kāi)引入的css文件合搅;
  • 靜態(tài)資源設(shè)置的含義
    • 代碼:app.use(express.static("./public"))
    • 含義:在express中多搀,設(shè)置靜態(tài)資源的請(qǐng)求路徑為public目錄下;
    • 驗(yàn)證:在地址欄中輸入localhost:8080/index.html地址灾部,指的含義是查找到public目錄下的index.html康铭,打開(kāi)并渲染到頁(yè)面上;
    • 在index.html文件中有l(wèi)ink引入的css文件赌髓;如:<link href="/css/bootstrap.css">从藤;其中l(wèi)ink的href會(huì)發(fā)送請(qǐng)求;相當(dāng)于在地址欄中輸入localhost:8080/css/bootstrap.css地址锁蠕;即夷野,在public目錄下查找css文件夾下的bootstrap.css文件,打開(kāi)并渲染到頁(yè)面中匿沛;
    • 結(jié)論:
      • 設(shè)置了靜態(tài)資源的路徑扫责;則在地址欄中尋找的文件都是在public目錄下查找,如果查找到逃呼,則渲染鳖孤,查找不到,則會(huì)查看其它的請(qǐng)求是否存在此地址抡笼;
      • 打開(kāi)html或ejs文件中苏揣,通過(guò)link或script或img中的href或src等引入文件,都會(huì)向服務(wù)器發(fā)送請(qǐng)求推姻;會(huì)默認(rèn)在public目錄下查找平匈;
  • 簡(jiǎn)單的實(shí)現(xiàn)index.ejs文件的頁(yè)面打開(kāi)渲染:
    • index.ejs文件,通過(guò)設(shè)置get請(qǐng)求:app.get("/",function(req,res){ res.render("index")};);即:在地址欄中輸入"/",后可執(zhí)行匿名函數(shù)增炭;在匿名函數(shù)中通過(guò)res.render來(lái)默認(rèn)打開(kāi)views目錄下的index.ejs文件忍燥;
    • 打開(kāi)index.ejs文件后,里面引入的href和src再次發(fā)送多個(gè)請(qǐng)求隙姿;在設(shè)置的靜態(tài)資源目錄public文件夾下查找文件梅垄;然后打開(kāi)渲染;
    • 代碼:
      • index.ejs文件代碼:
       <!DOCTYPE html>
       <html lang="zh-CN">
       <head>
           <meta charset="utf-8">
           <title>模板</title>
           <link href="css/bootstrap.css" rel="stylesheet">
       </head>
       <body>
       <h1>你好输玷,世界队丝!</h1>
       <script src="js/jquery.js"></script>
       <script src="js/bootstrap.js"></script>
       </body>
       </html>
      
      • app.js服務(wù)器代碼:
       const express=require("express");
       const app=express();
       const router=require("./controller/router");//引入自定義模塊,必須添加相對(duì)路徑欲鹏;
       app.listen(8080);
       
       //發(fā)送請(qǐng)求机久,靜態(tài)渲染頁(yè)面
       app.use(express.static("./public"));
       //設(shè)置模板引擎
       app.set("view engine","ejs");
       //通過(guò)"/"來(lái)發(fā)送請(qǐng)求,打開(kāi)views下的index.ejs文件
       app.get("/",router.showIndex);
      
      • router.js管理器代碼:
       exports.showIndex=function (req, res) {
           res.render("index")
       };
      

項(xiàng)目開(kāi)發(fā)

  • 搭建靜態(tài)頁(yè)面index.ejs赔嚎;利用bootstrap模板來(lái)創(chuàng)建頁(yè)面布局膘盖;
    • 頁(yè)面中相冊(cè)的個(gè)數(shù)取決于uploads目錄下文件夾的個(gè)數(shù);
    • 在頁(yè)面中利用ejs模板創(chuàng)建for循環(huán)尽狠,在服務(wù)器中通過(guò)render()傳送參數(shù)衔憨;即在router.js管理器中獲取參數(shù);router.js再去models中獲取數(shù)據(jù)袄膏;然后最終傳送給views中ejs頁(yè)面;
  • 獲取磁盤(pán)中uploads目錄下文件夾的個(gè)數(shù)掺冠;
    • 在models中files.js中獲取數(shù)據(jù)沉馆,導(dǎo)出數(shù)據(jù);利用fs文件系統(tǒng)中的readdir()來(lái)獲取文件夾下所有的文件德崭,再通過(guò)fs.stat()獲取每個(gè)文件的狀態(tài)stats斥黑,判斷stats.isDirectory()是否為true;如果文件是文件夾,則返回true;
    • 通過(guò)自執(zhí)行函數(shù)和遞歸函數(shù)眉厨,將異步強(qiáng)制變成同步锌奴;然后待遍歷完,輸出數(shù)組憾股;
    • 在匿名函數(shù)中如何輸出文件:通過(guò)callback參數(shù)鹿蜀;注意傳出的數(shù)據(jù)包括err錯(cuò)誤信息;
    • 在router.js中引入自定義模塊files.js服球,添加相對(duì)路徑茴恰;通過(guò)匿名函數(shù)中的參數(shù)拿到文件夾信息;然后通過(guò)res.render()傳送給ejs文件使用斩熊;
    • 注意點(diǎn):
      • 在使用fs.readdir(path,()=>{})時(shí)往枣,path路徑為"./uploads",其中"./"拿到的是根目錄;不是"../"拿到根目錄分冈;
      • 數(shù)據(jù)的輸出通過(guò)回調(diào)函數(shù)圾另,將異步操作中的結(jié)果輸出,但要注意輸出不同時(shí)刻的err信息雕沉;在成功輸出數(shù)據(jù)時(shí)盯捌,賦值為null,這樣在if(err)條件語(yǔ)句中蘑秽,就不會(huì)走語(yǔ)句饺著;
    • 代碼:
      • ejs代碼:
       <div class="container">
           <div class="row">
               <% for(var i=0; i<albums.length; i++){%>
                   <div class="col-xs-6 col-md-3">
                       <a href="/" class="thumbnail">
                           <img src="/img/01.jpg" alt="文件夾圖片">
                       </a>
                       <h5 style="text-align: center;"><%= albums[i]%></h5>
                   </div>
               <% }%>
           </div>
       </div>
      
      • app.js代碼:app.get("/",router.showIndex);
      • router.js代碼:
       //引入models中的files.js模塊;
       const modFiles=require("../models/files");
       //顯示首頁(yè)
       exports.showIndex=function (req, res) {
           modFiles.showAllAlbums(function(err,albums){
               if(err){
                   res.send(err);
                   return;//阻斷程序執(zhí)行肠牲;
               }
               res.render("index",{
                   albums
               })
           });
       };
      
      • files.js代碼:
       //用于生產(chǎn)數(shù)據(jù)幼衰,然后輸給router.js使用;
       const fs=require("fs");
       exports.showAllAlbums=function (callback) {//數(shù)據(jù)以回調(diào)函數(shù)的形式輸出缀雳;
           fs.readdir("./uploads",(err,files)=>{//地址為根目錄下的地址渡嚣;
               if(err){
                   callback(err,null);
                   return;
               }
               var ary=[];
               //把異步操作強(qiáng)制變成了同步操作;
               (function interator(i){
                   if(i>=files.length){
                       callback(null,ary);//null代表不會(huì)走if(err)條件肥印;
                       return;//阻斷程序執(zhí)行识椰;
                   }
                   fs.stat("./uploads/"+files[i],(err,stats)=>{
                       if(err){
                           callback(err,null);
                           return;
                       }
                       if(stats.isDirectory()){
                           ary.push(files[i]);
                       }
                       interator(++i);
                   })
               })(0);
           });
       };
      
  • 點(diǎn)擊文件夾后發(fā)送請(qǐng)求,打開(kāi)文件夾下的所有文件深碱;
    • 發(fā)送請(qǐng)求:在地址欄中輸入文件夾名字后腹鹉,即發(fā)送了get請(qǐng)求,使其獲的數(shù)據(jù)并打開(kāi)渲染敷硅;在index.ejs中每一個(gè)文件夾都在一個(gè)a標(biāo)簽中功咒,設(shè)置href為<a href="/<%= albums[i]%>" class="thumbnail">,即根據(jù)文件夾的名字不同绞蹦,發(fā)送不同的請(qǐng)求力奋;跟地址欄中輸入localhost:8080/大學(xué)是一樣的效果;從而實(shí)現(xiàn)頁(yè)面的跳轉(zhuǎn)幽七;
    • 打開(kāi)頁(yè)面景殷;需要新建一個(gè)showImg.ejs文件,里面是新的內(nèi)容澡屡;在發(fā)送/:albumsImg請(qǐng)求后猿挚,在files.js中打開(kāi)該文件夾,獲取文件夾下所有的文件挪蹭,通過(guò)fs.isFile()篩選出不是文件夾的文件亭饵;通過(guò)匿名函數(shù)傳出;然后渲染到頁(yè)面上梁厉,展示出相應(yīng)個(gè)數(shù)和名字的圖集辜羊;
    • 在頁(yè)面渲染中打開(kāi)img圖片踏兜;在files.js中只能拿到文件夾下的文件個(gè)數(shù)和文件名稱(chēng);無(wú)法打開(kāi)渲染八秃;res.render的作用是碱妆,打開(kāi)showImg.ejs文件,并且給其傳數(shù)據(jù)昔驱;只能渲染頁(yè)面疹尾,不能打開(kāi)img圖片;
    • 呈現(xiàn)img圖片在頁(yè)面中骤肛,需要img標(biāo)簽中的src再次發(fā)送強(qiáng)求纳本,服務(wù)器接受進(jìn)行響應(yīng);所以腋颠,需要再設(shè)置靜態(tài)資源到./uploads目錄下繁成,指的是,發(fā)送來(lái)的請(qǐng)求閑雜public目錄下找文件淑玫,如果找不到巾腕,就到uploads目錄下查找,找到文件絮蒿,渲染打開(kāi)文件尊搬;
    • 注意1:img中src的路徑需要注意;當(dāng)showImg.ejs被渲染到頁(yè)面上的時(shí)候土涝,src才開(kāi)始發(fā)送請(qǐng)求佛寿;包括css和js也會(huì)發(fā)送請(qǐng)求;
      • img的src設(shè)置時(shí)有兩種方式回铛;1)<img src="/<%= albumsImg%>/<%= albums[i]%>" alt="文件夾圖片">狗准,在地址中添加文件夾路徑;2)<img src="<%= albums[i]%>" alt="文件夾圖片">茵肃,在地址中不添加文件夾路徑但是不能添加"/",可能的原因是在地址欄中已經(jīng)存在http://localhost:8080/大學(xué)/;
      • css和js文件src中必須添加"/"袭祟,不能省略验残;
    • 注意2:使用req.params.albumsImg獲取請(qǐng)求地址時(shí),除了文件夾地址巾乳,還會(huì)得到favicon.ico您没,所以需要在獲取文件夾下文件的函數(shù)中,阻止favicon.ico運(yùn)行胆绊;
    • 代碼:
      • showImg.ejs代碼:
       <!DOCTYPE html>
       <html lang="zh-CN">
       <head>
           <meta charset="utf-8">
           <title>展示圖片</title>
           <link href="/css/bootstrap.css" rel="stylesheet">
       </head>
       <body>
       <% include include/header.ejs%>
       <section class="container">
           <ol class="breadcrumb">
               <li><a href="/">全部相冊(cè)</a></li>
               <li class="active"><%= albumsImg%></li>
           </ol>
       </section>
       <div class="container">
           <div class="row">
               <% for(var i=0; i<albums.length; i++){%>
                   <div class="col-xs-6 col-md-3">
                       <span class="thumbnail">
                           <img src="/<%= albumsImg%>/<%= albums[i]%>" alt="文件夾圖片">
                       </span>
                       <h5 style="text-align: center;"><%= albumsName[i]%></h5>
                   </div>
               <% }%>
           </div>
       </div>
       <script src="/js/jquery.js"></script>
       <script src="/js/bootstrap.js"></script>
       </body>
       </html>
      
      • app.js代碼:
       const express=require("express");
       const app=express();
       const router=require("./controller");//引入自定義模塊氨鹏,必須添加相對(duì)路徑;因?yàn)閏ontroller創(chuàng)建了package.json文件压状,在里面設(shè)置了main屬性仆抵,設(shè)置默認(rèn)的入口文件為router.js文件跟继;
       app.listen(8080);
       
       //發(fā)送請(qǐng)求,靜態(tài)渲染頁(yè)面
       //1.設(shè)置靜態(tài)資源路徑在public目錄下镣丑,用于渲染引入的css文件和js文件舔糖;
       app.use(express.static("./public"));
       //2.設(shè)置靜態(tài)資源路徑在uploads目錄下,用于渲染img圖片莺匠;
       app.use(express.static("./uploads"));
       
       //設(shè)置模板引擎
       app.set("view engine","ejs");
       //通過(guò)"/"來(lái)發(fā)送請(qǐng)求金吗,打開(kāi)views下的index.ejs文件
       app.get("/",router.showIndex);
       //發(fā)送get請(qǐng)求:地址:"/大學(xué)",打開(kāi)views下的showImg.ejs文件趣竣;
       app.get("/:albumsImg",router.showImg);
      
      • router.js代碼:
       //顯示相冊(cè)文件夾中的圖片
       exports.showImg=function (req, res) {
           var albumsImg=req.params.albumsImg;
           modFiles.showAlbumsImgs(albumsImg,function (err,albums,albumsName) {
               //如果有錯(cuò)誤摇庙,則顯示在頁(yè)面上,并阻斷程序執(zhí)行遥缕;
               if(err){
                   res.send(err);//send后面可以寫(xiě)return;
                   return;//必須阻斷程序執(zhí)行卫袒;
               }
               res.render("showImg",{
                   albumsImg,
                   albums,
                   albumsName
               })
           });
       };
      
      • files.js代碼:
       //獲取地址欄中發(fā)送的地址文件夾下的所有圖片文件;生成數(shù)組導(dǎo)出通砍;
       exports.showAlbumsImgs=function (albumsImg, callback) {
           //albumsImg是地址欄中的文件夾名稱(chēng)玛臂;callback用來(lái)導(dǎo)出數(shù)據(jù);
           //讀取文件夾下的文件
           fs.readdir("./uploads/"+albumsImg,function (err, files) {
               if(err){
                   callback("讀取文件夾失敗",null,null);
                   return;
               }
               var albums=[];
               var albumsName=[];
               (function interator(i) {
                   if(i>=files.length){
                       callback(null,albums,albumsName);
                       return;
                   }
                   fs.stat("./uploads/"+albumsImg+"/"+files[i],function (err, stats) {
                       if(err){
                           callback("讀取文件夾下的文件失敗",null,null);
                           return;
                       }
                       if(stats.isFile()){
                           //成立封孙,則證明不是文件夾
                           albums.push(files[i]);
                           albumsName.push(path.parse(files[i]).name);
                       }
                       interator(++i);
                   })
               })(0);
           })
       };
      
  • 頁(yè)面的操作:
    • 提煉出兩個(gè)ejs頁(yè)面中的公共的代碼迹冤,放在views下的include文件夾下的header.ejs文件中;這樣在文件中引入此文件即可虎忌;
    • 優(yōu)點(diǎn):當(dāng)頁(yè)面公共部分的代碼泡徙,發(fā)生變化,只需在header.ejs文件中修改即可膜蠢,否則堪藐,還需分別再兩個(gè)文件中修改;
    • 引入include.ejs文件代碼:<% include include/header.ejs%>挑围,其中include/header.ejs為相對(duì)路徑礁竞,無(wú)需加引號(hào);
  • 圖片上傳功能
    • 思路:
      • 創(chuàng)建form.ejs表單頁(yè)面杉辙;通過(guò)form表單來(lái)提交數(shù)據(jù)模捂;
      • 發(fā)送get請(qǐng)求,通過(guò)header.ejs中的上傳a標(biāo)簽href設(shè)置地址蜘矢,點(diǎn)擊發(fā)送請(qǐng)求狂男;打開(kāi)form.ejs頁(yè)面;傳送數(shù)據(jù)品腹;用于select表單中獲取文件夾數(shù)據(jù)岖食;
      • 發(fā)送post請(qǐng)求,通過(guò)表單中submit提交按鈕舞吭,設(shè)置form中的action和method泡垃;點(diǎn)擊發(fā)送post請(qǐng)求析珊;
      • 在router.js中通過(guò)formidable模塊來(lái)獲取上傳的數(shù)據(jù);
        • 新建form對(duì)象兔毙;var form= new formidable.IncomingForm()唾琼;
        • 設(shè)置上傳地址;form.uploadDir="./uploads/"澎剥;
        • 通過(guò)form.parse()拿數(shù)據(jù)锡溯;=》fields:表單上傳參數(shù)組成的對(duì)象;files:表單file中name組成的對(duì)象哑姚;用于獲取上傳圖片的路徑名字祭饭;以及上傳之前的名字;
        • 通過(guò)files.tupian.size叙量,拿到上傳文件的大小倡蝙,然后進(jìn)行判斷,如果大于某值绞佩,則用fs.unlink()刪除已經(jīng)上傳的文件寺鸥;注意,在條件判斷中設(shè)置return品山;阻斷程序向下運(yùn)行胆建;
        • 通過(guò)fs.rename()將oldpath改為newpath,修改原來(lái)文件名字并移動(dòng)該文件到新的路徑下肘交;
      • 修改成功后笆载,打開(kāi)對(duì)應(yīng)文件夾的圖集;調(diào)用modFiles.showAlbumsImgs(albumsImg,function (err,albums,albumsName){})涯呻;
      • 修改成功后凉驻,可以通過(guò) res.redirect("/中學(xué)")來(lái)進(jìn)行重定向頁(yè)面跳轉(zhuǎn);
    • 注意點(diǎn):
      • 設(shè)置get請(qǐng)求"/upload"時(shí)复罐,必須放在app.get("/:albumsImg",router.showImg);前面涝登,否則,不會(huì)走該請(qǐng)求效诅;必須將嚴(yán)格的請(qǐng)求放在不嚴(yán)格的請(qǐng)求的前面缀拭;
      • form表單中,seclect和file必須設(shè)置name值填帽,否則無(wú)法獲取數(shù)據(jù);seclect的name值用來(lái)獲取放在哪個(gè)文件夾下咙好,file的name值是用來(lái)作為files對(duì)象中屬性名來(lái)獲取上傳文件的數(shù)據(jù)的篡腌;
      • form表單中的action設(shè)置請(qǐng)求地址,method設(shè)置post請(qǐng)求勾效,enctype設(shè)置大文件下的類(lèi)型嘹悼;
      • 利用formidable模塊獲取files對(duì)象后叛甫,path屬性拿到的是路徑加文件名;作為oldpath杨伙;newpath包含相對(duì)路徑和文件名其监;相對(duì)路徑設(shè)置為uploads下的對(duì)應(yīng)文件夾中;
      • 在修改名字后限匣,原來(lái)上傳的文件會(huì)被移動(dòng)到新的路徑下抖苦;
      • 在設(shè)置上傳地址時(shí)地址后面必須加"/",否則米死,無(wú)法使用锌历;如form.uploadDir="./uploads/";
      • 注意異步和同步問(wèn)題;
    • 代碼:
      • form-upload.ejs代碼:
       <!DOCTYPE html>
       <html lang="zh-CN">
       <head>
           <meta charset="utf-8">
           <title>表單上傳文件</title>
           <link href="/css/bootstrap.css" rel="stylesheet">
       </head>
       <body>
       <% include include/header.ejs%>
       <section class="container">
           <form action="/doupload" method="post" enctype="multipart/form-data">
               <div class="form-group">
                   <label for="wenjian">相冊(cè)目錄</label>
                   <select class="form-control" name="wenjianjia" id="wenjian">
                       <% for(var i=0; i<albums.length; i++){%>
                           <option><%= albums[i]%></option>
                       <%}%>
                   </select>
               </div>
               <div class="form-group">
                   <label for="InputFile">上傳文件路徑</label>
                   <input type="file" id="InputFile" name="tupian">
               </div>
               <button type="submit" class="btn btn-primary">上傳</button>
           </form>
       </section>
       <script src="/js/jquery.js"></script>
       <script src="/js/bootstrap.js"></script>
       </body>
       </html>
      
      • app.js代碼:
       /發(fā)送get請(qǐng)求:地址:"/upload",打開(kāi)views下的form.ejs文件峦筒;
       app.get("/upload",router.upload);
       //發(fā)送post請(qǐng)求究西,地址:"/doupload",上傳文件物喷;
       app.post("/doupload",router.doUpload);
       //以上代碼必須放在下面代碼前面卤材;
       //發(fā)送get請(qǐng)求:地址:"/大學(xué)",打開(kāi)views下的showImg.ejs文件峦失;
       app.get("/:albumsImg",router.showImg);
      
      • router.js代碼:
       //上傳文件獲取數(shù)據(jù)
       exports.doUpload=function (req, res) {
           //新建一個(gè)form對(duì)象
           var form= new formidable.IncomingForm();
           //設(shè)置上傳地址
           form.uploadDir="./uploads/";
           //解析文件
           form.parse(req,(err,fields,files)=>{
               //修改文件名扇丛,放在指定文件夾下
               var oldpath=files.tupian.path;
               var newpath=form.uploadDir+fields.wenjianjia+"/"+files.tupian.name;
               fs.rename(oldpath,newpath,function (err) {
                   if(err){
                       res.send("修改名字失敗");
                       return;
                   }else{
                       //res.send("上傳成功");//注意異步問(wèn)題;所以此代碼不能寫(xiě)在外面宠进;
                       //當(dāng)上傳成功后晕拆,跳轉(zhuǎn)到相應(yīng)的文件夾中打開(kāi);
                       var albumsImg=fields.wenjianjia;
                       modFiles.showAlbumsImgs(albumsImg,function (err,albums,albumsName) {
                           //如果有錯(cuò)誤材蹬,則顯示在頁(yè)面上实幕,并阻斷程序執(zhí)行;
                           if(err){
                               res.send(err);//send后面可以寫(xiě)return;
                               return;//必須阻斷程序執(zhí)行堤器;
                           }
                           res.render("showImg",{
                               albumsImg,
                               albums,
                               albumsName
                           })
                       });
                   }
               })
           });
       };
      
  • 接盤(pán)俠
    • 在最后設(shè)置use請(qǐng)求昆庇,請(qǐng)求地址為"/",即所有的地址都可以進(jìn)入請(qǐng)求闸溃;渲染打開(kāi)404.ejs文件整吆,顯示404頁(yè)面;
    • 代碼:
     //設(shè)置404頁(yè)面辉川,用來(lái)接底
     app.use("/",function (req, res) {
         res.render("404");//打開(kāi)404.ejs文件表蝙;
     });
    
    • 利用middleware中間件來(lái)設(shè)置錯(cuò)誤流,當(dāng)進(jìn)入一個(gè)請(qǐng)求后乓旗,如果出現(xiàn)err府蛇,則通過(guò)next(),來(lái)向下接著請(qǐng)求屿愚,最終到達(dá)use請(qǐng)求汇跨,渲染404頁(yè)面务荆;
    • 在router.js文件中所有請(qǐng)求的匿名函數(shù);均要設(shè)置next,當(dāng)err情況下穷遂,設(shè)置next(),并阻斷程序執(zhí)行函匕;
    • files.js文件中err不需要設(shè)置next(),因?yàn)橥ㄟ^(guò)callback已經(jīng)將err返回到router.js中;
    • 這樣設(shè)置蚪黑,也可以解決地址具體地址和廣泛地址的影響盅惜;
    • 注意:send()后面不能設(shè)置任何東西;可以寫(xiě)return;

項(xiàng)目開(kāi)發(fā)中的架構(gòu)格局

  • 文件分類(lèi)及作用
    • MVC結(jié)構(gòu):
      • M:models:用來(lái)獲取后臺(tái)的數(shù)據(jù)庫(kù)祠锣,通過(guò)exports輸出給controller管理器酷窥;
        • 創(chuàng)建files.js文件,作為后臺(tái)數(shù)據(jù)的模塊伴网;通過(guò)exports來(lái)傳出數(shù)據(jù)蓬推,在router.js管理器中引入此模塊,用于獲取傳出數(shù)據(jù)澡腾;
      • V:views: 目錄下存在ejs文件沸伏,作為瀏覽器視圖的渲染文件;
        • 存儲(chǔ)ejs文件动分,用于頁(yè)面的打開(kāi)渲染毅糟;
        • 創(chuàng)建include文件夾,里面創(chuàng)建header.ejs文件澜公,作為ejs文件的公共部分代碼姆另;通過(guò)<% include include/header.ejs%>引入到其他文件中;
      • C:controller:管理器坟乾;用來(lái)連接models和views迹辐;
        • 作用:作為一個(gè)管理者,在views中通過(guò)render來(lái)打開(kāi)ejs文件甚侣,在數(shù)據(jù)庫(kù)或models中拿數(shù)據(jù)明吩;
        • 創(chuàng)建router.js文件,作為數(shù)據(jù)的管理器殷费;通過(guò)exports來(lái)傳出數(shù)據(jù)印荔;在app.js中引入此模塊來(lái)獲取數(shù)據(jù);
        • 創(chuàng)建package.json文件详羡,通過(guò)設(shè)置里面的main屬性仍律,來(lái)設(shè)置默認(rèn)入口文件router.js;則在app.js服務(wù)器文件中引入模塊時(shí)实柠,可以直接引入controller文件夾染苛,如const router=require("./controller");
      • 三者之間的關(guān)系:
        • 當(dāng)服務(wù)器中接受到瀏覽器發(fā)送的請(qǐng)求后,向controller管理器請(qǐng)求;如代碼:app.get("/",router.showIndex);茶行;router.js中設(shè)置匿名函數(shù);渲染頁(yè)面登钥;
        • 當(dāng)瀏覽器中需要uploads文件夾下的文件夾個(gè)數(shù)時(shí)畔师,向controller管理器要數(shù)據(jù);controller再向models后臺(tái)數(shù)據(jù)庫(kù)中查找獲饶晾巍看锉;models數(shù)據(jù)也通過(guò)exports輸出數(shù)據(jù);
    • public文件夾:用于存儲(chǔ)靜態(tài)文件塔鳍;如css,js文件伯铣;通過(guò)在服務(wù)器中設(shè)置靜態(tài)渲染來(lái)引用文件;
    • app.js:為入口文件轮纫,用于創(chuàng)建服務(wù)器來(lái)前后臺(tái)交互腔寡;
    • package.json:用于記錄項(xiàng)目依賴(lài)的文件;
    • readme.md:讀者讀的文檔掌唾,用于解讀項(xiàng)目放前;
  • 請(qǐng)求及目的
    • get請(qǐng)求,是為了渲染打開(kāi)頁(yè)面糯彬;
      • get-"/"=>打開(kāi)index.ejs;即凭语,打開(kāi)圖片首頁(yè),根據(jù)uploads下文件夾的個(gè)數(shù)撩扒,呈現(xiàn)出相應(yīng)個(gè)數(shù)的圖集似扔;
      • get-"/:albumsImg" => 打開(kāi)showImg.ejs;即呈現(xiàn)出每個(gè)albumsImg文件夾下的圖片搓谆;
      • get-"/upload" => 打開(kāi)form上傳文件表單炒辉;用于上傳圖片文件;
    • post請(qǐng)求挽拔,是真正做一些功能的辆脸,如上傳文件;
      • post-"/doupload" => 通過(guò)表單中的submit提交按鈕螃诅,來(lái)發(fā)送post請(qǐng)求啡氢,進(jìn)行圖片文件的上傳;
    • use請(qǐng)求:請(qǐng)求地址設(shè)置為"/"术裸,可以省略倘是,作為接盤(pán)俠;
      • use-"/" => 打開(kāi)404.ejs文件袭艺,呈現(xiàn)404頁(yè)面搀崭,配合middleware中間件使用;

項(xiàng)目開(kāi)發(fā)中的知識(shí)點(diǎn)

  • 在controller文件夾中創(chuàng)建package.json文件,里面設(shè)置main屬性瘤睹,來(lái)設(shè)置默認(rèn)的入口文件為router.js升敲,這樣在app.js服務(wù)器中引入模塊時(shí),只引入文件夾controller轰传;即:const router=require("./controller");
  • 在項(xiàng)目開(kāi)發(fā)中如果匿名函數(shù)中存在err錯(cuò)誤代碼驴党,必須設(shè)置相應(yīng)的條件語(yǔ)句,然后傳出錯(cuò)誤信息获茬;后面一定要加return港庄,阻斷程序執(zhí)行;
  • 使用req.params.albumsImg獲取請(qǐng)求地址時(shí)恕曲,除了文件夾地址鹏氧,還會(huì)得到favicon.ico,所以需要在獲取文件夾下文件的函數(shù)中佩谣,阻止favicon.ico運(yùn)行把还;
  • 1M等于1024K,1K等于1024字節(jié),文件上傳時(shí)稿存,通過(guò)files.tupian.size來(lái)獲取上傳文件的大小笨篷,單位為字節(jié);
  • 接盤(pán)use請(qǐng)求和middleware的設(shè)置
    • use請(qǐng)求地址為"/"瓣履,可以省略率翅;當(dāng)所有請(qǐng)求都不成立的時(shí)候,最后請(qǐng)求use的匿名函數(shù)袖迎,打開(kāi)404頁(yè)面文件冕臭;
    • 前提是在每個(gè)請(qǐng)求的匿名函數(shù)中設(shè)置middleware中間件;即next();當(dāng)err時(shí)設(shè)置next(),并阻斷程序執(zhí)行燕锥;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末辜贵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子归形,更是在濱河造成了極大的恐慌托慨,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暇榴,死亡現(xiàn)場(chǎng)離奇詭異厚棵,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蔼紧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)婆硬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人奸例,你說(shuō)我怎么就攤上這事彬犯。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵谐区,是天一觀的道長(zhǎng)湖蜕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)卢佣,這世上最難降的妖魔是什么重荠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮虚茶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘仇参。我一直安慰自己嘹叫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布诈乒。 她就那樣靜靜地躺著罩扇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪怕磨。 梳的紋絲不亂的頭發(fā)上喂饥,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音肠鲫,去河邊找鬼员帮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛导饲,可吹牛的內(nèi)容都是我干的捞高。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼渣锦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼硝岗!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起袋毙,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤型檀,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后听盖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體胀溺,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年媳溺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了月幌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡悬蔽,死狀恐怖扯躺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤录语,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布倍啥,位于F島的核電站,受9級(jí)特大地震影響澎埠,放射性物質(zhì)發(fā)生泄漏虽缕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一蒲稳、第九天 我趴在偏房一處隱蔽的房頂上張望氮趋。 院中可真熱鬧,春花似錦江耀、人聲如沸剩胁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)昵观。三九已至,卻和暖如春舌稀,著一層夾襖步出監(jiān)牢的瞬間啊犬,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工壁查, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留觉至,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓潮罪,卻偏偏與公主長(zhǎng)得像康谆,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嫉到,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容