用node.js实现mvc相册资源管理器
摘要:通过前两天的学习我大概学了了,用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相册资源管理器的更多相关文章
- node.js express mvc轻量级框架实践
本文记录的是笔者最近抽私下时间给朋友做的一个时时彩自动下注系统,比较简单,主要也是为了学习一下node.js. 其实逻辑没什么可以深谈的,主要是想说说这套代码结构.结构如下图: js的代码比较难以维护 ...
- 转 10 个最佳的 Node.js 的 MVC 框架
10 个最佳的 Node.js 的 MVC 框架 oschina 发布于: 2014年02月24日 (33评) 分享到: 收藏 +322 Node.js 是一个基于Chrome JavaScri ...
- 10 个最佳的 Node.js 的 MVC 框架
补充:http://nokit.org/ https://thinkjs.org/zh-cn/doc/index.html Node.js 是一个基于Chrome JavaScript 运行时建立的一 ...
- 用node搭建简单的静态资源管理器
我们都知道,老牌的3p服务器都是自带静态资源管理器的.但是node不同,它没有web容器,它的路由地址和真实地址可以没有联系,所有node的优点,是可以把路由做得相当漂亮. 但静态资源管理器也是必不可 ...
- Node.js与Sails~方法拦截器policies
回到目录 policies sails的方法拦截器类似于.net mvc里的Filter,即它可以作用在controller的action上,在服务器响应指定action之前,对这个action进行拦 ...
- Node.js+Express+MVC+Mysql小白创建新项目
1.打开CMD命令窗口,这一步不会的,回家休息,不要看了 2.npm install -g yo 等待时间看个人电脑情况. 如果没有npm命令,建议先安装npm ,npm安装介绍:https://d ...
- Node.js 包管理器 NPM 讲解
包管理器又称软件包管理系统,它是在电脑中自动安装.配制.卸载和升级软件包的工具组合,在各种系统软件和应用软件的安装管理中均有广泛应用.对于我们业务开发也很受益,相同的东西不必重复去造轮子. 每个工具或 ...
- Node.js教程系列~目录
Node.js这个东西在近几年火起来了,而且会一直火下去,无论在infoq还是在cnblogs,csdn上,都可以到处看到它的样子,它主推的应该就是异步式I/O 吧,是的,设计的很完美,很吸引人,虽然 ...
- Node.js +Express+MongoDB+mogoose+ejs+bootstrap+jquery
Node.js + MongoDB 项目实战(二) 创建项目 在项目实战(一)中,已经配置好了开发环境(详见:http://www.cnblogs.com/jameslong/articles/34 ...
随机推荐
- linux 更新源miss问题
1.之前新装的linuxMint 执行 apt-get install vim 安装失败 发现原因是源更新失败导致,后来执行apt-get update 发现老是获取失败,查了google总结出以下解 ...
- php 文档操作
ftp_mkdir() 函数在 FTP 服务器上建立新目录. 语法 ftp_mkdir(ftp_connection,dir) 参数 描述 ftp_connection 必需.规定要使用的 FTP 连 ...
- 记录一次Session偶尔获取不到的解决过程
导读 平台下某子系统有密码登录需求,初步考虑用Session,登录后设置Session[key]=value;Session中若某key对应的Session,即Session[key]为null则限制 ...
- MyBatis 一、二级缓存和自定义缓存
1.一级缓存 MyBatis 默认开启了一级缓存,一级缓存是在SqlSession 层面进行缓存的.即,同一个SqlSession ,多次调用同一个Mapper和同一个方法的同一个参数,只会进行一 ...
- RunLoop想入门,看这篇就够了
前言 刚刚听到RunLoop的时候我也是一脸懵逼,这是什么,有什么用呢,逼格貌似还挺高.然后就开始尝试去搞懂它,去找博客,但是几乎所有的博客都是枯燥乏味的,都是讲概念,然后给个实例,对于我这个小白来说 ...
- SparkStreaming动态读取配置文件
SparkStreaming动态读取配置文件 标签: SparkStreaming HDFS 配置文件 MySql 需求 要实现SparkStreaming在流处理过程中能动态的获取到配置文件的改变 ...
- Java 浏览器兼容模式
现在设计的东西,很多浏览器不兼容.下面贴出代码.测试在360和IE浏览器下,可以兼容的 <!doctype html><html><head> <met ...
- (转载) Java子类与父类之间的对象转换
在使用Java的多态机制时,常常使用的一个特性便是子类和父类之间的对象转换.从子类向父类的转换称为向上转换(upcasting),通过向上转换,我们能够在编写程序时采用通用程序设计的思想,在需要使用子 ...
- cmd 更改计算机名
bat 更改计算机名 不用重启电脑就生效^_^ @Echo off Color 0A title --更改计算机名 :A cls echo. echo. [0]退出 echo. echo. 不用重启 ...
- PHP扩展开发 第一课 为什么要写扩展及hello world
PHP扩展开发其实很简单.那为什么要扩展开发呢. 这里咱们以实际的案例进行对比. 第一步,进入 php源码包 http://www.php20.com/forum.php?m ... =159&a ...