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等技术运用到这个工程中是一种质的提高和成功,善于总结的人永远都是最有底气的人,由于积累了足够多的错误才能更加自信的去面对未知的技术和困难,永远保持一颗谦逊的心,成功就在眼前!!!!!!