WebStorm下的node.jscss
1、回顧與繼續html
在前面,咱們知道了node.js的基本框架和思路,在這些原生環境下咱們對node.js的設計思想有了比較深入的認識,而且具備了編寫大型程序的能力了,可是程序的代碼可能會比較拉雜,所以,咱們就須要用到現有的框架了,在咱們的社會上,不須要造太多的輪子,而須要在更高層次上去設計‘車’,所以使用別人作好的模板去完成本身的業務是一個比較節省時間而且有創造性的事情,在node.js中咱們有太多的輪子,好比說express框架,爲咱們提供了封裝好的不少作事情的接口,咱們能夠方便的進行組裝和搭配,好比ejs、jade這些現有的模板引擎,爲咱們提供了不少可擴展的能力,在這個基礎上咱們能夠最大限度的發揮本身的創造性,去完成本身業務。前端
2、Express框架
Express框架是後臺的Node框架,因此和jQuery、zepto、yui、bootstrap都不一個東西。Express在後臺的受歡迎的程度,和jQuery同樣,就是企業的事實上的標準。原生Node開發,會發現有不少問題。好比:node
Express的哲學是在你的想法和服務器之間充當薄薄的一層。這並不意味着他不夠健壯,或者沒有足夠的有用特性,而是儘可能少干預你,讓你充分表達本身的思想,同時提供一些有用的東西。一樣的,咱們仍是使用npm來安裝該框架:--save參數,表示自動修改package.json文件,自動添加依賴項。jquery
1 npm install --save express
用express框架寫一個最簡單的程序:正則表達式
1 var express=require("express"); 2
3 var app=new express(); 4 app.get("/",function(req,res){ 5 res.send("success!"); 6 }); 7 app.get(/\/student\/([\d]{10})/,function (req,res) { 8 res.send("student info:"+req.params[0]); 9 }) 10 app.listen(3100);
在這裏咱們首先引用了該框架,其次經過new關鍵字建立了該對象,以後,咱們對於首頁的訪問返回成功,對於路徑名爲‘/student/十位數字’的訪問,咱們經過正則表達式返回了相應的學號,在這裏之因此可使用req的params[0]返回相應的數字,是由於咱們在正則表達式中用()對相應的地方進行了選中,一樣的,咱們還能夠對更長的路徑名進行這樣的過濾,道理是同樣的,一樣的咱們能夠看到get方法能夠對用戶訪問的路徑進行解析,固然post主要是對錶單進行處理的,另外在這裏除了用正則表達式以外咱們還可使用 : 來對咱們想要表達的文字進行表示,好比這裏咱們就能夠寫爲「/student/:id」,那麼咱們就能夠獲得id的值了,只要再使用正則表達式判斷位數就能夠了。數據庫
1 app.get("/student/:id",function(req,res){ 2 var id = req.params["id"]; 3 var reg= /^[\d]{6}$/; //正則驗證
4 if(reg.test(id)){ 5 res.send(id); 6 }else{ 7 res.send("請檢查格式"); 8 } 9 });
運行結果以下:express
在這裏咱們還可使用use方法來暴露靜態文件,也叫靜態文件伺服能力:npm
app.use(express.static("./public"));
這樣咱們就能夠在網址中輸入public文件夾下的任何路徑而不須要輸入public,很好的隱藏了一些重要的內容、迷惑了黑客的視線。而且假如public文件夾下有一個a.html文件,咱們能夠直接用127.0.0.1:3100/a.html來訪問,更強大的是若是public文件夾下有一個index.html文件,則直接輸入127.0.0.1:3100便可以訪問。編程
a、get用法:
GET請求的參數在URL中,在原生Node中,須要使用url模塊來識別參數字符串。在Express中,不須要使用url模塊了。能夠直接使用req.query對象。
當用get請求訪問一個網址的時候,作什麼事情:
app.get("網址",function(req,res){
});
這裏的網址,不分大小寫,也就是說,路由是
app.get("/AAb",function(req,res){
res.send("你好");
});
實際上小寫的訪問也行。
全部的GET參數,? 後面的都已經被忽略。 錨點#也被忽略,路由到/a , 實際/a?id=2&sex=nan 也能被處理。
表單能夠本身提交到本身上。
app.get("/",function(req,res){
res.render("form");
});
適合進行 RESTful路由設計。簡單說,就是一個路徑,可是http method不一樣,對這個頁面的使用也不一樣。
/student/345345
get 讀取學生信息
add 添加學生信息
delete 刪除學生信息
1 <!doctype html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title></title>
6 </head>
7 <body>
8 <form action="#" method="post">
9 <input type="text" name="name"/>
10 <input type="text" name="age"/>
11 <input type="submit"/>
12 </form>
13 </body>
14 </html>
b、post用法:
POST請求在express中不能直接得到,必須使用body-parser模塊。使用後,將能夠用req.body獲得參數。可是若是表單中含有文件上傳,那麼仍是須要使用formidable模塊。當用post訪問一個網址的時候可使用下面的格式:
app.post("網址",function(req,res){
});
app.post("/",function(req,res){
//將數據添加進入數據庫
res.send("成功");
});
c、all的用法:
若是想處理這個網址的任何method的請求,那麼寫all
app.all("/",function(){
});
3、中間件
咱們輸入的網址就像一個水流,中間件就像是過濾水流的大網,水流中的某些東西流經某一個地方被阻擋住的話就不會再向下面流去了,所以網的大小(中間件)的先後順序很是重要,若是get、post回調函數中,沒有next參數,那麼就匹配上第一個路由,就不會往下匹配了。若是想往下匹配的話,那麼須要寫next()。
1 app.get("/",function(req,res,next){ 2 console.log("1"); 3 next(); 4 }); 5 app.get("/",function(req,res){ 6 console.log("2"); 7 });
讓咱們看一個例子,下面兩個路由,感受沒有關係:
1 app.get("/:username/:id",function(req,res){ 2 console.log("1"); 3 res.send("用戶信息" + req.params.username); 4 }); 5 app.get("/admin/login",function(req,res){ 6 console.log("2"); 7 res.send("管理員登陸"); 8 });
可是實際上衝突了,由於admin能夠當作用戶名 login能夠當作id。
解決方法1:交換位置。
也就是說,express中全部的路由(中間件)的順序相當重要。
匹配上第一個,就不會往下匹配了。 具體的往上寫,抽象的往下寫。
1 app.get("/admin/login",function(req,res){ 2 console.log("2"); 3 res.send("管理員登陸"); 4 }); 5 app.get("/:username/:id",function(req,res){ 6 console.log("1"); 7 res.send("用戶信息" + req.params.username); 8 });
解決方法2: 使用next()
app.get("/:username/:id",function(req,res,next){ var username = req.params.username; //檢索數據庫,若是username不存在,那麼next()
if(檢索數據庫){ console.log("1"); res.send("用戶信息"); }else{ next(); } }); app.get("/admin/login",function(req,res){ console.log("2"); res.send("管理員登陸"); });
路由get、post這些東西,就是中間件,中間件講究順序,匹配上第一個以後,就不會日後匹配了。next函數纔可以繼續日後匹配。
app.use()也是一箇中間件。與get、post不一樣的是,他的網址不是精確匹配的。而是可以有小文件夾拓展的。
好比網址: http://127.0.0.1:3000/admin/aa/bb/cc/dd
1 app.use("/admin",function(req,res){ 2 res.write(req.originalUrl + "\n"); // /admin/aa/bb/cc/dd
3 res.write(req.baseUrl + "\n"); // /admin
4 res.write(req.path + "\n"); // /aa/bb/cc/dd
5 res.end("你好"); 6 });
當不寫路徑的時候,實際上就至關於"/",就是全部網址
app.use(function(req,res,next){ console.log(new Date()); next(); });
app.use()就給了咱們增長一些特定功能的便利場所。
大多數狀況下,渲染內容用res.render(),將會根據views中的模板文件進行渲染。若是不想使用views文件夾,想本身設置文件夾名字,那麼
app.set("views","aaaa");
若是想寫一個快速測試頁,固然可使用res.send()。這個函數將根據內容,自動幫咱們設置了Content-Type頭部和200狀態碼。send()只能用一次,和end同樣。和end不同在於可以自動設置MIME類型。若是想使用不一樣的狀態碼,能夠:
1 res.status(404).send('Sorry, we cannot find that!');
若是想使用不一樣的Content-Type,能夠:
res.set('Content-Type', 'text/html');
4、小小相冊中的大大智慧
講了這麼多理論性的東西,咱們須要實戰來檢驗本身的掌握程度,所以,在這裏咱們使用node.js爲服務器,製做一個相冊管理器,咱們能夠在上面上傳相片,也能夠查看不一樣文件夾中的相片,在這裏咱們使用MVC模型來進行項目的佈局、設計和實現!
程序的功能:
一、B/S模式,使用node.js做爲服務器,瀏覽器爲客戶端,能夠遠程訪問,至少保持局域網內的可訪問性。
二、具備圖片的上傳能力,能夠將特定的圖片上傳到特定的文件夾中,對上傳圖片的大小有限制,上傳的圖片具備統一格式的命名。
三、具備高效路由能力,能夠經過靜態路由功能找到相應文件夾下的圖片而且顯示出來。
四、須要用到bootstrap、express框架、jQuery支持、ejs模板引擎、MVC等多種技術。
首先讓咱們看一下工程的目錄:
其中node_modules中至少包含express、ejs、silly-datetime、formidable這些基本的模塊。工程採用了MVC的模式,具備很強的可擴展性,在app.js是整個工程的配置和啓動,在controller中是對app.js中的命令的一種解析和執行,對於不一樣的請求採用不一樣的方法進行響應,在models中是對數據的一種管理,好比讀取文件的目錄或者文件夾的目錄等,而且返回這些數據給controller,而controller拿着這些數據交給views去渲染,而且顯示相應的頁面,能夠說後端的呈遞徹底就是對數據的操做和顯示,這些數據包括簡單的數值、變量、對象、數組、字節流、字符流、多媒體數據等,而前端主要用來進行渲染和展示,在這裏咱們仍是使用ejs模板引擎將獲得的數據進行渲染和顯示,而且使用了bootstrap技術和JQuery技術來增長美化程度,更快更好地完善咱們的功能。uploads靜態文件夾用來保存上傳過來的圖片,temp文件夾用來間接地呈遞咱們上傳的圖片,做爲中轉。public靜態文件夾主要存放一下瀏覽器能夠直接訪問到的數據,好比css、HTML、圖片、bootstrap等數據和文件,這就是文件的結構了。
4.一、app.js文件
1 var express=require("express"); 2 var app=express(); 3 var router=require("./controller/router.js") 4 app.set("view engine","ejs"); 5
6 app.use(express.static("./public")); 7 app.use(express.static("./uploads")); 8 9 app.get("/",router.showIndex); 10 11 app.get("/up",router.showUp); 12 app.post("/up",router.doPost); 13
14 app.get("/:albumName",router.showAlbum); 15
16 app.use(function (req,res) { 17 res.render("err"); 18 }); 19 app.listen(3100);
這是整個工程的指導文件,對於每個請求都將經過該文件進行分發和處理,能夠說是核心樞紐,實現使用了ejs模板引擎,默認文件夾views爲將要渲染的文件夾。其次暴露了兩個文件夾做爲靜態文件夾,提供了對這兩個文件夾下的全部文件的路由能力。而後對於首頁訪問命令,直接經過controller層進行細節的處理,經過MVC框架來呈現首頁,而後是對於文件上傳的兩個界面,首先咱們須要跳轉到上傳文件界面,這個時候使用get命令便可完成,而且返回填寫信息界面,所以走了一遍MVC,其次是填寫完表單須要提交的時候,咱們須要使用post命令來提交表單,而且經過formidable來處理上傳的圖片信息。而後是對於圖片文件夾的訪問,咱們對於不一樣的文件夾呈現不一樣的圖片列表,最後是對於任意上面處理不了的信息,咱們返回錯誤頁面,固然也是經過ejs渲染以後來呈現。而後令程序監聽3000之後的某個端口,避免衝突。
4.二、controller下面的router.js文件
1 var file=require("../models/file.js"); 2 var formidable = require('formidable'); 3 var sd = require("silly-datetime"); 4 var path = require("path"); 5 var fs=require("fs"); 6 //首頁信息
7 exports.showIndex=function(req,res){ 8 file.getAllAlbums(function (err,allAlbums) { 9 if(err){ 10 res.render("err"); 11 return; 12 } 13 res.render("index", 14 {"albums":allAlbums} 15 ); 16 }) 17 } 18 //顯示圖片列表
19 exports.showAlbum=function(req,res){ 20 var albumName=req.params.albumName; 21 file.getAllImagesByAlbumname(albumName,function(err,imageArray){ 22 if(err){ 23 res.render("err"); 24 return; 25 } 26 res.render("album", 27 { 28 "albumName":albumName, "images":imageArray 29 } 30 ); 31 }); 32 } 33 //顯示填寫上傳文件ejs
34 exports.showUp=function(req,res){ 35 file.getAllAlbums(function(err,albums) 36 { 37 res.render("up", { 38 "allAlbums": albums 39 }); 40 }); 41 } 42 //提交上傳的文件並處理,持久化
43 exports.doPost=function(req,res){ 44 var form = new formidable.IncomingForm(); 45 form.uploadDir = "./temp/"; 46 form.parse(req, function (err, fields, files) { 47 console.log(fields); 48 console.log(files); 49 var size=parseInt(files.picture.size); 50 // if(size>1024*1024)
51 // {
52 // res.send("圖片尺寸應小於1M");
53 // //刪除圖片
54 // fs.unlink(files.picture.path);
55 // console.log("刪除成功!")
56 // return;
57 // }
58 var ttt = sd.format(new Date(), 'YYYYMMDDHHmmss'); 59 var ran = parseInt(Math.random() * 89999 + 10000); 60 var extname = path.extname(files.picture.name); 61 var oldpath = __dirname + "/../" + files.picture.path; 62 var newpath = __dirname + "/../uploads/" +fields.folder+"/"+ ttt + ran + extname; 63 console.log(oldpath); 64 console.log(newpath); 65 fs.rename(oldpath, newpath, function (err) { 66 if (err) { 67 throw Error("更名失敗"); 68 console.log("失敗"); 69 return; 70 } 71 res.render("success"); 72 console.log("成功"); 73 return; 74 }); 75 }); 76 }
這個文件能夠說是承上啓下,首先分派一個任務交由models層來完成,獲得相應的數據,而後拿着這些數據經過res.render()來渲染而且顯示,而且暴露本身,可讓app.js訪問到。在這裏,咱們須要注意異步編程的特色,必定要用callback函數來處理那些須要讀寫文件系統或者其餘I/O設備的操做,否則將會出現異常和錯誤。
4.三、models文件夾下面的file.js文件
1 var fs = require("fs"); 2 //返回全部文件夾列表
3 exports.getAllAlbums=function(callback){ 4 fs.readdir("./uploads",function (err,files) { 5 if(err){ 6 callback("讀取文件夾失敗!",null); 7 return; 8 } 9 var allAlbums=[]; 10 (function iterator(i) { 11 if(i==files.length) 12 { 13 callback (null,allAlbums); 14 return; 15 } 16 fs.stat("./uploads/"+files[i],function (err,stats) { 17 if(err){ 18 callback("解析文件夾失敗!"+files[i],null); 19 return; 20 } 21 if(stats.isDirectory()) 22 { 23 allAlbums.push(files[i]); 24 } 25 iterator(i+1) 26 }); 27 })(0); 28 }); 29 } 30 //根據文件夾的名字來找到該文件夾下的全部圖片文件而且返回
31 exports.getAllImagesByAlbumname =function(albumname,callback){ 32 fs.readdir("./uploads/"+albumname,function (err,files) { 33 if(err){ 34 callback("讀取文件夾失敗!",null); 35 return; 36 } 37 var allImages=[]; 38 (function iterator(i) { 39 if(i==files.length) 40 { 41 callback (null,allImages); 42 console.log(allImages); 43 return; 44 } 45 fs.stat("./uploads/"+albumname+"/"+files[i],function (err,stats) { 46 if(err){ 47 callback("解析文件失敗"+files[i],null); 48 return; 49 } 50 if(stats.isFile()) 51 { 52 allImages.push(files[i]); 53 } 54 iterator(i+1) 55 }); 56 })(0); 57 }); 58 }
其實咱們仔細思考一下就能明白,對文件的數據進行讀,咱們只有這兩種操做,一種是返回全部文件夾列表,另外一種是根據文件夾的名字來找到該文件夾下的全部圖片文件而且返回,這兩種操做就是徹底精細的,適用於咱們項目需求的原子操做,能夠用來複用。在這裏咱們使用了iterator來保證同步執行。值得注意的是,若是咱們文件讀取失敗或者文件夾讀取失敗,會提示isFile()或者isDirectory()未定義,這個時候,咱們須要作的就是仔細看一下文件或者文件夾是否由於路徑的緣由而沒有讀取成功。這點在編程中十分重要。還有crtl+alt+I(i),注意這個地方必定是I,而不是L,能夠對咱們選中的(crtl+A)代碼進行整理,這些編程技巧十分重要!!!!!!
4.四、views文件夾下面的ejs文件
完成了這些咱們就須要關注一下前端的實現了,在這裏咱們經過ejs來進行渲染,一樣的,咱們借鑑了bootstrap中的模板,在www.bootcss.com網站中咱們能夠清楚的找到屬於咱們的組件和實例,而且搭建最基本的前端界面,本程序就是從上面借鑑的!咱們從這個網站中下載bootstrap,而後解壓以後,放到咱們的public文件夾下面去,而後在該網站中找到「起步」,從中下載最簡單的使用代碼,而後在「全局CSS樣式」和「組件」中,咱們根據本身的業務要求選擇適合本身使用的控件進行佈局,具體的細節這裏就略去不提了,最重要的是bootstrap中對jQuery有依賴,所以咱們須要從網上下載jQuery的函數庫,就是一個文件而已,而後放到bootstrap文件夾中的js文件夾下,這樣咱們就完成了準備工做!!!!!!
準備完成了以後,讓咱們看一下ejs代碼,下面的是index.ejs的代碼:
1 <!DOCTYPE html>
2 <html lang="zh-CN">
3 <head>
4 <meta charset="utf-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7 <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! -->
8 <title>小小相冊</title>
9 <link href="css/bootstrap.min.css" rel="stylesheet">
10 <style type="text/css"> 11 .row h4{ 12 text-align:center; 13 } 14 </style>
15 </head>
16 <body>
17
18
19 <nav class="navbar navbar-default">
20 <div class="container-fluid">
21 <!-- Brand and toggle get grouped for better mobile display -->
22 <div class="navbar-header">
23 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
24 <span class="sr-only">Toggle navigation</span>
25 <span class="icon-bar"></span>
26 <span class="icon-bar"></span>
27 <span class="icon-bar"></span>
28 </button>
29 <a class="navbar-brand" href="#">小小相冊</a>
30 </div>
31
32 <!-- Collect the nav links, forms, and other content for toggling -->
33 <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
34 <ul class="nav navbar-nav">
35 <li class="active"><a href="#">所有相冊 <span class="sr-only">(current)</span></a></li>
36 <li><a href="/up">上傳</a></li>
37 </ul>
38 </div>
39 </div>
40 </nav>
41 <div class="container"> 42 <div class="row"> 43 <% for (var i=0;i<albums.length;i++){%> 44 <div class="col-xs-6 col-md-3"> 45 <a href="<%=albums[i]%>" class="thumbnail"> 46 <img src="images/folder.jpg" alt=""> 47 </a> 48 <h4><%=albums[i]%></h4> 49 </div> 50 <%}%> 51 </div> 52 </div>
53
54 <script src="js/jquery-1.11.3.js"></script> 55 <script src="js/bootstrap.min.js"></script>
56 </body>
57 </html>
一樣的,其餘的ejs文件渲染以下:
album.ejs:
1 <!DOCTYPE html>
2 <html lang="zh-CN">
3 <head>
4 <meta charset="utf-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7 <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! -->
8 <title>小小相冊</title>
9 <link href="/css/bootstrap.min.css" rel="stylesheet">
10 <style type="text/css">
11 .row h4{ 12 text-align:center; 13 } 14 </style>
15 </head>
16 <body>
17
18 <nav class="navbar navbar-default">
19 <div class="container-fluid">
20 <!-- Brand and toggle get grouped for better mobile display -->
21 <div class="navbar-header">
22 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
23 <span class="sr-only">Toggle navigation</span>
24 <span class="icon-bar"></span>
25 <span class="icon-bar"></span>
26 <span class="icon-bar"></span>
27 </button>
28 <a class="navbar-brand" href="#">小小相冊</a>
29 </div>
30
31 <!-- Collect the nav links, forms, and other content for toggling -->
32 <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
33 <ul class="nav navbar-nav">
34 <li ><a href="../">所有相冊 <span class="sr-only">(current)</span></a></li>
35 <li><a href="/up">上傳</a></li>
36 </ul>
37 </div><!-- /.navbar-collapse -->
38 </div><!-- /.container-fluid -->
39 </nav>
40 <ol class="breadcrumb">
41 <li><a href="../">所有相冊</a></li>
42 <li class="active"><%=albumName%></li>
43 </ol>
44 <div class="container">
45 <div class="row">
46 <% for (var i=0;i<images.length;i++){%>
47 <div class="col-xs-6 col-md-3">
48 <a href="#" class="thumbnail">
49 <img src="<%=images[i]%>" alt="">
50 </a>
51 <h4><%=images[i]%></h4>
52 </div>
53 <%}%>
54 </div>
55 </div>
56 <script src="/js/jquery-1.11.3.js"></script>
57 <script src="/js/bootstrap.min.js"></script>
58 </body>
59 </html>
err.ejs:
1 <!DOCTYPE html>
2 <html lang="zh-CN">
3 <head>
4 <meta charset="utf-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7 <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! -->
8 <title>小小相冊</title>
9 <link href="/css/bootstrap.min.css" rel="stylesheet">
10 <style type="text/css">
11 .row h4{ 12 text-align:center; 13 } 14 </style>
15 </head>
16 <body>
17
18
19 <nav class="navbar navbar-default">
20 <div class="container-fluid">
21 <!-- Brand and toggle get grouped for better mobile display -->
22 <div class="navbar-header">
23 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
24 <span class="sr-only">Toggle navigation</span>
25 <span class="icon-bar"></span>
26 <span class="icon-bar"></span>
27 <span class="icon-bar"></span>
28 </button>
29 <a class="navbar-brand" href="#">小小相冊</a>
30 </div>
31
32 <!-- Collect the nav links, forms, and other content for toggling -->
33 <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
34 <ul class="nav navbar-nav">
35 <li class="active"><a href="../">所有相冊 <span class="sr-only">(current)</span></a></li>
36 <li><a href="/up">上傳</a></li>
37 </ul>
38 </div><!-- /.navbar-collapse -->
39 </div><!-- /.container-fluid -->
40 </nav>
41 <div class="container">
42 <img src="/images/1.jpg" alt="">
43 </div>
44
45 <script src="/js/jquery-1.11.3.js"></script>
46 <script src="/js/bootstrap.min.js"></script>
47 </body>
48 </html>
success.ejs:
1 <!DOCTYPE html>
2 <html lang="zh-CN">
3 <head>
4 <meta charset="utf-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7 <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! -->
8 <title>小小相冊</title>
9 <link href="/css/bootstrap.min.css" rel="stylesheet">
10 <style type="text/css">
11 .row h4{ 12 text-align:center; 13 } 14 </style>
15 </head>
16 <body>
17
18
19 <nav class="navbar navbar-default">
20 <div class="container-fluid">
21 <!-- Brand and toggle get grouped for better mobile display -->
22 <div class="navbar-header">
23 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
24 <span class="sr-only">Toggle navigation</span>
25 <span class="icon-bar"></span>
26 <span class="icon-bar"></span>
27 <span class="icon-bar"></span>
28 </button>
29 <a class="navbar-brand" href="#">小小相冊</a>
30 </div>
31
32 <!-- Collect the nav links, forms, and other content for toggling -->
33 <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
34 <ul class="nav navbar-nav">
35 <li class="active"><a href="../">所有相冊 <span class="sr-only">(current)</span></a></li>
36 <li><a href="/up">上傳</a></li>
37 </ul>
38 </div><!-- /.navbar-collapse -->
39 </div><!-- /.container-fluid -->
40 </nav>
41 <div class="container">
42 <img src="/images/2.jpg" alt="">
43 </div>
44
45 <script src="/js/jquery-1.11.3.js"></script>
46 <script src="/js/bootstrap.min.js"></script>
47 </body>
48 </html>
up.ejs:
1 <!DOCTYPE html>
2 <html lang="zh-CN">
3 <head>
4 <meta charset="utf-8">
5 <meta http-equiv="X-UA-Compatible" content="IE=edge">
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7 <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! -->
8 <title>小小相冊</title>
9 <link href="/css/bootstrap.min.css" rel="stylesheet">
10 <style type="text/css">
11 .row h4{ 12 text-align:center; 13 } 14 </style>
15 </head>
16 <body>
17
18 <nav class="navbar navbar-default">
19 <div class="container-fluid">
20 <!-- Brand and toggle get grouped for better mobile display -->
21 <div class="navbar-header">
22 <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
23 <span class="sr-only">Toggle navigation</span>
24 <span class="icon-bar"></span>
25 <span class="icon-bar"></span>
26 <span class="icon-bar"></span>
27 </button>
28 <a class="navbar-brand" href="#">小小相冊</a>
29 </div>
30
31 <!-- Collect the nav links, forms, and other content for toggling -->
32 <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
33 <ul class="nav navbar-nav">
34 <li ><a href="../">所有相冊 <span class="sr-only">(current)</span></a></li>
35 <li><a href="/up">上傳</a></li>
36 </ul>
37 </div><!-- /.navbar-collapse -->
38 </div><!-- /.container-fluid -->
39 </nav>
40
41 <div class="container"> 42 <div class="row"> 43 <form style="width:40%" method="post" action="#" enctype="multipart/form-data"> 44 <div class="form-group"> 45 <label for="exampleInputEmail1">選擇文件夾</label> 46 <select class="form-control" name="folder"> 47 <% for(var i=0;i<allAlbums.length;i++){%> 48 <option><%=allAlbums[i]%></option> 49 <%}%> 50 </select> 51 </div> 52 53 <div class="form-group"> 54 <label for="exampleInputFile" >選擇圖片</label> 55 <input type="file" id="exampleInputFile" name="picture"> 56 <p class="help-block">Example block-level help text here.</p> 57 </div> 58 59 <button type="submit" class="btn btn-default">Submit</button> 60 </form> 61 </div> 62 </div>
63 <script src="/js/jquery-1.11.3.js"></script>
64 <script src="/js/bootstrap.min.js"></script>
65 </body>
66 </html>
最後是咱們的總依賴package.json,在這裏咱們對本身的工程進行佈局和顯示:
1 { 2 "name": "little-album", 3 "version": "1.0.0", 4 "description": "", 5 "main": "app.js", 6 "dependencies": { 7 "body-parser": "^1.18.2", 8 "ejs": "^2.5.7", 9 "express": "^4.16.1", 10 "formidable": "^1.1.1", 11 "silly-datetime": "^0.1.2" 12 }, 13 "devDependencies": {}, 14 "scripts": { 15 "test": "echo \"Error: no test specified\" && exit 1" 16 }, 17 "author": "", 18 "license": "ISC" 19 }
綜上就是咱們的程序了,算是一個demo,咱們能夠對其進行擴充,咱們的架子已經搭好了,之後就是按着這樣的套路來不斷地增磚添瓦,而且對前端進行美工。讓咱們來看一下運行效果:
因而可知程序完美執行了相應的任務,完成了相應的功能!!!!!!
工程文件已經壓縮而且放在百度雲上,網址爲:http://pan.baidu.com/s/1gfL7UM3, 密碼爲:z6qv!!!!!!
6、總結
這也是一篇比較耗時的文章,算是對本身能力的一種錘鍊,花了本身一兩天的時間去學習和整理,最後使用一個工程來說本身的所學所思所說所講都用在了實踐中,從最簡單的實踐中,一步步的去粗取精,最後實現了一個文件資源管理器的部分功能,若是想作的話還能夠繼續進行,文件夾的建立、修改和刪除、文件的增刪改查、移動到其餘文件夾等功能,方法都和上傳相似,到了這裏總算能夠歇一下子了,領略一下站在半山腰看着山下的風景的美麗,對於nodejs咱們已經掌握的不錯了,可是還遠遠算不上精通,其實沒有那我的能夠徹底對一門技術精通,即便是創造這門技術的人也沒有絕對的把握去這樣說,可是咱們的確已經入門了,而且有了不錯的成果和收穫,將本身從其餘語言中學到的MVC等技術運用到這個工程中是一種質的提高和成功,善於總結的人永遠都是最有底氣的人,由於積累了足夠多的錯誤才能更加自信的去面對未知的技術和困難,永遠保持一顆謙遜的心,成功就在眼前!!!!!!