app.js
/* littleAlbum --.idea --controller(控制层相当于action层) --package.json --router.js --models(做事的是model层相当于dao层) --file.js --node_modules(引入的其他模块) --public(静态资源) --css --bootstrap.css --fonts --glyphicons-halflings-regular.ttf --images --404.jpg --js --npm.js --jquery-1.11.3.min.js --bootstrap.js --tempup --uploads(上传的文件) --views(View层,数据通过ejs模版注入) --album.ejs --err.ejs --index.ejs --up.ejs --app.js --package.json */ var express = require("express"); var app = express(); //控制器 var router = require("./controller");//引入的是文件夹,文件夹里面要有index.js或者package.json文件里面的入口js文件。 //设置模板引擎 app.set("view engine", "ejs"); //路由中间件,网址正好匹配上了public下面的文件(全路径匹配),就直接返回。匹配不上就向下路由, app.use(express.static("./public"));//静态页面,静态页面里面的资源路径如果与app.get()里面的路径重复,就只走这里。资源图片cssjs都是在public文件夹,页面都是在views文件夹。 //网址正好匹配上了uploads下面的文件(全路径匹配),就直接返回。 app.use(express.static("./uploads")); //上面匹配了就停止,上面没有匹配上,就跑到下面来匹配,首页 app.get("/", router.showIndex); app.get("/:albumName", router.showAlbum); app.get("/up", router.showUp); app.post("/up", router.doPost); console.log(6); //404,上面都没有匹配到就404页面 app.use(function (req, res) { res.render("err"); }); app.listen(3000);
router.js
/** * Created by Danny on 2015/9/22 15:30. */ var file = require("../models/file.js"); var formidable = require('formidable'); var path = require("path"); var fs = require("fs"); var sd = require("silly-datetime"); //首页 exports.showIndex = function(req,res,next){ console.log(1); /* 错误的:传统思维,不是node的思维: res.render("index",{ "albums" : file.getAllAlbums() getAllAlbums里面是异步的,不能这么写,只能等这个异步执行完才行,就用回调函数 }); */ //这就是Node.js的编程思维,就是所有的东西,都是异步的 //file函数的返回值通过回调函数实现。 file.getAllAlbums(function(err,allAlabums){//实参回调函数的定义 //err是字符串 if(err){ next(); //交给下面适合他的中间件 return; } res.render("index",{ "albums" : allAlabums }); }) } //相册页 exports.showAlbum = function(req,res,next){ console.log(2); //遍历相册中的所有图片 var albumName = req.params.albumName; //具体业务交给model file.getAllImagesByAlbumName(albumName,function(err,imagesArray){ if(err){ next(); //交给下面的中间件 return; } res.render("album",{ "albumname" : albumName, "images" : imagesArray }); }); }; //显示上传 exports.showUp = function(req,res){//中间件有req、res console.log(3); //命令file模块(我们自己写的函数)调用getAllAlbums函数 //得到所有文件夹名字之后做的事情,写在回调函数里面 file.getAllAlbums( function(err,albums){res.render("up",{albums : albums} ); }); }; //上传表单 exports.doPost = function(req,res){ console.log(4); var form = new formidable.IncomingForm(); form.uploadDir = path.normalize(__dirname + "/../tempup/");// '../表示向上回溯一级' form.parse(req, function(err, fields, files,next) { console.log(fields); console.log(files); //改名 if(err){ next(); //这个中间件不受理这个请求了,往下走 return; } //判断文件尺寸 var size = parseInt(files.tupian.size); if(size > 2000){ res.send("图片尺寸应该小于1M"); //删除图片 fs.unlink(files.tupian.path); return; } var ttt = sd.format(new Date(), 'YYYYMMDDHHmmss'); var ran = parseInt(Math.random() * 89999 + 10000); var extname = path.extname(files.tupian.name); var wenjianjia = fields.wenjianjia; var oldpath = files.tupian.path ; var newpath = path.normalize(__dirname + "/../uploads/" + wenjianjia + "/" + ttt + ran + extname); fs.rename(oldpath,newpath,function(err){ if(err){ res.send("改名失败"); return; } res.send("成功"); }); }); return; }
file.js
/** * Created by Danny on 2015/9/22 16:32. */ var fs = require("fs"); //这个函数的callback中含有两个参数,一个是err //另一个是存放所有文件夹名字的array。 exports.getAllAlbums = function(callback){ fs.readdir("./uploads",function(err,files){ if(err){ callback("没有找到uploads文件",null); } var allAlbums = []; (function iterator(i){ if(i == files.length){ //遍历结束,这个线程执行完毕, console.log(allAlbums); callback(null,allAlbums);//这个线程执行完毕调用回调函数。 return; } fs.stat("./uploads/" + files[i],function(err,stats){ if(err){ callback("找不到文件" + files[i] , null); } if(stats.isDirectory()){ allAlbums.push(files[i]); } iterator(i + 1); }); })(0); }); } //通过文件名,得到所有图片 exports.getAllImagesByAlbumName = function(albumName,callback){ fs.readdir("./uploads/" + albumName,function(err,files){ if(err){ callback("没有找到uploads文件",null); return; } var allImages = []; (function iterator(i){ if(i == files.length){ //遍历结束 console.log(allImages); callback(null,allImages); return; } fs.stat("./uploads/" + albumName + "/" + files[i],function(err,stats){ if(err){ callback("找不到文件" + files[i] , null); return; } if(stats.isFile()){ allImages.push(files[i]); } iterator(i + 1); }); })(0); }); }
albm.ejs
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>小小相册</title> <link href="/css/bootstrap.min.css" rel="stylesheet"> <style type="text/css"> .row h4{ text-align: center; } </style> </head> <body> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">小小相册</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li><a href="/">全部相册<span class="sr-only">(current)</span></a></li> <li><a href="/up">上传</a></li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container"> <ol class="breadcrumb"> <li><a href="/">全部相册</a></li> <li class="active"><%=albumname%></li> </ol> <div class="row"> <% for(var i = 0 ; i < images.length ; i++){ %> <div class="col-xs-6 col-md-3"> <a href="#" class="thumbnail"> <img src="<%=images[i]%>" alt="..."> </a> <h4> </h4> </div> <%}%> </div> </div> <script src="/js/jquery-1.11.3.min.js"></script> <script src="/js/bootstrap.min.js"></script> </body> </html>
err.ejs
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>小小相册</title> <link href="/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">小小相册</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li><a href="#">全部相册<span class="sr-only">(current)</span></a></li> <li><a href="#">上传</a></li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container"> <img src="/images/404.jpg" alt=""/> </div> <script src="/js/jquery-1.11.3.min.js"></script> <script src="/js/bootstrap.min.js"></script> </body> </html>
up.ejs
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>小小相册</title> <link href="/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">小小相册</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li><a href="#">全部相册<span class="sr-only">(current)</span></a></li> <li><a href="#">上传</a></li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container"> <div class="row"> <form style="40%;" method="post" action="#" enctype="multipart/form-data"> <div class="form-group"> <label for="exampleInputEmail1">选择文件夹</label> <select class="form-control" name="wenjianjia"> <% for(var i = 0 ; i < albums.length ; i++){%> <option><%= albums[i] %></option> <%}%> </select> </div> <div class="form-group"> <label for="exampleInputFile">选择图片</label> <p>尺寸小于2M</p> <input type="file" id="exampleInputFile" name="tupian"> </div> <button type="submit" class="btn btn-default">上传</button> </form> </div> </div> <script src="/js/jquery-1.11.3.min.js"></script> <script src="/js/bootstrap.min.js"></script> </body> </html>
index.ejs
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>小小相册</title> <link href="css/bootstrap.min.css" rel="stylesheet"> <style type="text/css"> .row h4{ text-align: center; } </style> </head> <body> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">小小相册</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="/">全部相册<span class="sr-only">(current)</span></a></li> <li><a href="/up">上传</a></li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container"> <div class="row"> <% for(var i = 0 ; i < albums.length ; i++){ %> <div class="col-xs-6 col-md-3"> <a href="<%= albums[i] %>" class="thumbnail"> <img src="images/wjj.jpg" alt="..."> </a> <h4><%= albums[i] %></h4> </div> <% } %> </div> </div> <script src="js/jquery-1.11.3.min.js"></script> <script src="js/bootstrap.min.js"></script> </body> </html>
jad.js