摘要:通过前两天的学习我大概学了了,用formidable模块文件上传,express框架,以及利用fs模块进行文件读取,今天我学习了如何用这些知识来制作相册,暂没有数据库,所以做的也是本地的资源管理器。根据本地存放照片文件夹,通过服务器来进行查看本地照片文件夹和上传照片到该文件夹

一、成品展示:

二、总体设计

三、实现代码

app.js

var express=require("express");
var app=express();
//控制器
var router=require("./controller");        //在package.json里设置了router.js为默认的js
//设置模版引擎
app.set("view engine","ejs"); //路由中间件
//静态页面
app.use(express.static('./public'));
app.use(express.static('./uploads'));
//get/的时候,上层函数回调的时候传入req,res
//首页 app.get("/",router.showIndex);
app.get("/up", router.showUp);
app.get('/:albumName',router.showAlbum);
app.post('/up',router.doPost) ;
//
app.use(function (req,res) { res.render("err"); });
app.listen();

用express静态出public和uploads文件夹,用来放资源文件,然后分别路由主页,相册文件夹,上传页面,上传表单处理。

然后在控制层的controller来控制前台和后台的交互

router.js

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) {
//错误的:传统的思维不是node的思维
// res.render("index",{
  //注意这里异步的,遇到阻塞,会直接呈递模版引擎,所以这种写法是错误的,小函数会没执行完,就呈递
    //     "albums":file.getAllAlbums()
// }); //这就是node.js的编程思维,就是所有的东西,都是异步的
//所以,内层函数,不是return回来东西,而是调用高层函数提供的
//回调函数。把数据当成回调函数的参数来使用
file.getAllAlbums(function (err,allAlabums) {      //这个函数就是callback
//err是字符串
if(err){
res.send(err);
return ;
}
res.render("index",{
"albums":allAlabums
});
});
} //相册页
exports.showAlbum=function (req,res) {
//遍历相册中的所有图片
var albumName=req.params.albumName;
//具体业务交给model
file.getAllImagesByAlbumName(albumName,function (err,imagesArray) {
if(err){
res.send(err);
return ;
}
res.render("album",{
"albumname":albumName,
"images":imagesArray
});
});
}; //显示上传
exports.showUp=function(req,res) {
//命令file模块(我们自己写的函数),调用getAllAlbums函数
//得到所有文件夹名字之后做的事情,写在回调函数里
file.getAllAlbums(function (err,albums) {
res.render("up",{
albums:albums
});
});
}; //上传表单
exports.doPost=function (req,res) {
var form=new formidable.IncomingForm();
form.uploadDir=path.normalize(__dirname+"/../tempup");          //上传到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,注意的是由于这里没用es6的先进写法,所以很多是异步语句,正常的return返回是不行的,需要递归迭代来获得所有数据,用callback回调处理

file.js

var fs=require("fs");

//这个函数的callback中含有两个参数,一个是err
//另一个是存放所有文件夹名字的array
exports.getAllAlbums=function (callback) {
fs.readdir("./uploads", function (err, files) {
if (err){
callback("没有找到uploads子文件夹",null);
}
var allAlbums = [];
console.log(files);
(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);
});
}

剩下的就是view视图层的前端样式了,用的ejs模板和bootstrap样式:

主页:index.ejs

<!DOCTYPE html>
<html>
<head>
<title>小小相册</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
<style>
.row h4{
text-align: center;
}
</style>
</head>
<body>
<!--<h1>小小相册</h1>-->
<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="data: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>

相册页:album.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>

上传页:up.ejs

<!DOCTYPE html>
<html>
<head>
<title>小小相册</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
<style>
.row h4{
text-align: center;
}
</style>
</head>
<body>
<!--<h1>小小相册</h1>-->
<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="#">上传</a></li> </ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav> <div class="container">
<div class="row">
<form 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>
<input type="file" id="exampleInputFile" name="tupian">
<p class="help-block">Example block-level help text here.</p>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div> </div> <script src="/js/jquery-1.11.3.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
</body>
</html>

注意上传模块用的formidable,获得的files,fields对象参数,是和表单标签样式name属性对应的。

错误页面:err.ejs

<!DOCTYPE html>
<html>
<head>
<title>小小相册</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
<style>
.row h4{
text-align: center;
}
</style>
</head>
<body>
<!--<h1>小小相册</h1>-->
<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="#">上传</a></li> </ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav> <div class="container"> <img src="<%=baseurl%>/images/404.jpg" alt="">
</div> <script src="/js/jquery-1.11.3.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
</body>
</html>

  

用node.js实现mvc相册资源管理器的更多相关文章

  1. node.js express mvc轻量级框架实践

    本文记录的是笔者最近抽私下时间给朋友做的一个时时彩自动下注系统,比较简单,主要也是为了学习一下node.js. 其实逻辑没什么可以深谈的,主要是想说说这套代码结构.结构如下图: js的代码比较难以维护 ...

  2. 转 10 个最佳的 Node.js 的 MVC 框架

    10 个最佳的 Node.js 的 MVC 框架 oschina 发布于: 2014年02月24日 (33评) 分享到:    收藏 +322 Node.js 是一个基于Chrome JavaScri ...

  3. 10 个最佳的 Node.js 的 MVC 框架

    补充:http://nokit.org/ https://thinkjs.org/zh-cn/doc/index.html Node.js 是一个基于Chrome JavaScript 运行时建立的一 ...

  4. 用node搭建简单的静态资源管理器

    我们都知道,老牌的3p服务器都是自带静态资源管理器的.但是node不同,它没有web容器,它的路由地址和真实地址可以没有联系,所有node的优点,是可以把路由做得相当漂亮. 但静态资源管理器也是必不可 ...

  5. Node.js与Sails~方法拦截器policies

    回到目录 policies sails的方法拦截器类似于.net mvc里的Filter,即它可以作用在controller的action上,在服务器响应指定action之前,对这个action进行拦 ...

  6. Node.js+Express+MVC+Mysql小白创建新项目

    1.打开CMD命令窗口,这一步不会的,回家休息,不要看了 2.npm install -g yo  等待时间看个人电脑情况. 如果没有npm命令,建议先安装npm ,npm安装介绍:https://d ...

  7. Node.js 包管理器 NPM 讲解

    包管理器又称软件包管理系统,它是在电脑中自动安装.配制.卸载和升级软件包的工具组合,在各种系统软件和应用软件的安装管理中均有广泛应用.对于我们业务开发也很受益,相同的东西不必重复去造轮子. 每个工具或 ...

  8. Node.js教程系列~目录

    Node.js这个东西在近几年火起来了,而且会一直火下去,无论在infoq还是在cnblogs,csdn上,都可以到处看到它的样子,它主推的应该就是异步式I/O 吧,是的,设计的很完美,很吸引人,虽然 ...

  9. Node.js +Express+MongoDB+mogoose+ejs+bootstrap+jquery

    Node.js + MongoDB 项目实战(二)  创建项目 在项目实战(一)中,已经配置好了开发环境(详见:http://www.cnblogs.com/jameslong/articles/34 ...

随机推荐

  1. 常用的Python代码段

    过滤列表 #filter out empty strings in a sting list list = [x for x in list if x.strip()!=''] 一行一行地读文件 wi ...

  2. C#中split分隔字符串的应用

    .用单个字符来分隔:string str="aaajbbbjccc";string[] sArray=str.Split('j');foreach(string i in sArr ...

  3. Makefile持续学习二

    Makefile概述 一.Makefile里有什么? Makefile里主要包含5个东西:显式规则.隐晦规则.变量定义.文件指示和注释 1.显式规则:显式规则说明如恶化生成一个或多的目标文件,包含要生 ...

  4. Redis 图形化监控方案 RedisLive 介绍

    作为一款开源的 Redis 图形化监控工具,RedisLive 提供对 Redis 实例的内存使用情况,接收的客户端命令,接收的请求数量以及键进行监控.RedisLive 的工作原理基于 Redis ...

  5. 熟悉的“if __name__ == '__main__':”究竟是啥?

    print(__name__) # 直接手动运行,打印"__main__",当做模块导入(别处import)时打印脚本名字即"name_main" if __n ...

  6. Python 面向对象(一) 基础

    Python 中一切皆对象 什么是面向对象? 面向对象就是将一些事物的共有特征抽象成类,从类来创建实例. 类class 可以理解为模版 比如人类,都具有身高.体重.年龄.性别.籍贯...等属性,但属性 ...

  7. Java 操作 Json

    1. 使用Gson构建Json 初始化 JsonObject jsonObject = new JsonObject(); 添加属性 jsonObject.addProperty("name ...

  8. ios判断手机号是否可用

    + (BOOL)valiMobile:(NSString *)mobileNum { if (mobileNum.length != 11) { return NO; } /** * 手机号码: // ...

  9. XSD详解二 - 简易元素、属性、内容限定

    一.XSD 简易元素 XML Schema 可定义 XML 文件的元素. 简易元素指那些只包含文本的元素.它不会包含任何其他的元素或属性. 1.什么是简易元素? 简易元素指那些仅包含文本的元素.它不会 ...

  10. 《Linux命令行与shell脚本编程大全》第二十五章 创建与数据库、web及电子邮件相关的脚本

    25.1 MySQL数据库 /* 但是我在虚拟机上安装的时候居然不提示输入密码. 这个可以参考http://blog.csdn.net/sinat_21302587/article/details/7 ...