• Node 实现一个MVC相册资源管理器


    暂没有数据库,所以做的也是本地的资源管理器。

    总体设计:

     app.js:

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

    用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,next) {
        //错误的,传统的思维,不是Node的思维。
        // res.render("index",{
        //     //注意这里异步的,遇到阻塞,会直接呈递模版引擎,所以这种写法是错误的,小函数会没执行完,就呈递了
        //     "albums" : file.getAllAlbums()
        // });
        //这就是Node.js的编程思维,就是所有的东西,都是异步的
        //所以,内层函数,不是return回来东西,而是调用高层函数提供的
        //回调函数。把数据当做回调函数的参数来使用。
        file.getAllAlbums(function (err,allAlbums) { //这个function就是callback
            //err是字符串
            if(err) {
                next();
                return;
            }
            res.render("index",{
                "albums" : allAlbums
            });
        })
    };
    
    //相册页
    exports.showAlbum = function (req,res,next) {
        //遍历相册中的所有图片
        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) {
        //命令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/");
        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 > 2000000) {
                 res.send("图片尺寸应该小于2M");
    
                //则删除这个文件
                fs.unlink("files.tupian.path",function () {
    
                });
                return;
            }
            var wenjianjia = fields.wenjianjia;
            var oldpath = files.tupian.path ;
            //还是加时间戳
            var ttt = sd.format(new Date(), "YYYMMDDHHmmss");
            var ran = parseInt(Math.random() * 89999 + 10000);
            var extname = path.extname(files.tupian.name);
            var newpath = path.normalize(__dirname + "/../uploads/" + wenjianjia + "/" + ttt + ran + extname);
            fs.rename(oldpath,newpath,function (err) {
                if(err) {
                    res.send("改名失败");
                    return;
                }
                res.send("成功");
            });
        });
    
    
    }

    底层的真正处理的模型层的file.js,注意的是由于这里没用es6的先进写法,所以很多是异步语句,正常的return返回是不行的,需要递归迭代来获得所有数据,用callback回调处理

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

    <!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>littleAlbum</title>
    
        <link href="css/bootstrap.min.css" rel="stylesheet">
    
        <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
        <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
        <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>
                    <li class="dropdown">
                        <ul class="dropdown-menu">
                            <li><a href="#">Action</a></li>
                            <li><a href="#">Another action</a></li>
                            <li><a href="#">Something else here</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">One more separated link</a></li>
                        </ul>
                    </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/wenjianjia2.jpg" alt="...">
                </a>
                <h4><%= albums[i] %></h4>
            </div>
            <% } %>
        </div>
    </div>
    <!--运行之后views和public是在一起的-->
    <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>littleAlbum</title>
    
        <link href="/css/bootstrap.min.css" rel="stylesheet">
    
        <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
        <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
        <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>
                    <li class="dropdown">
                        <ul class="dropdown-menu">
                            <li><a href="#">Action</a></li>
                            <li><a href="#">Another action</a></li>
                            <li><a href="#">Something else here</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">One more separated link</a></li>
                        </ul>
                    </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>
    <!--运行之后views和public是在一起的-->
    <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">
    
        <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
        <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
        <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>
                    <li class="dropdown">
                        <ul class="dropdown-menu">
                            <li><a href="#">Action</a></li>
                            <li><a href="#">Another action</a></li>
                            <li><a href="#">Something else here</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">One more separated link</a></li>
                        </ul>
                    </li>
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>
    
    <div class="container">
        <div class="row">
            <form style = " 40%" method="post" enctype="multipart/form-data" action = "#">
                <div class="form-group">
                    <label for="exampleInputFile">选择文件夹</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">
                    <p class="help-block">Example block-level help text here.</p>
                </div>
    
                <button type="submit" class="btn btn-default">上传</button>
            </form>
        </div>
    </div>
    <!--运行之后views和public是在一起的-->
    <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>littleAlbum</title>
    
        <link href="/css/bootstrap.min.css" rel="stylesheet">
    
        <script src="https://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
        <script src="https://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
        <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>
                    <li class="dropdown">
                        <ul class="dropdown-menu">
                            <li><a href="#">Action</a></li>
                            <li><a href="#">Another action</a></li>
                            <li><a href="#">Something else here</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">One more separated link</a></li>
                        </ul>
                    </li>
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>
    
    <div class="container">
        <img src="/images/404.jpg" alt="">
    </div>
    <!--运行之后views和public是在一起的-->
    <script src="/js/jquery-1.11.3.min.js"></script>
    <script src="/js/bootstrap.min.js"></script>
    </body>
    </html>

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

  • 相关阅读:
    Redis使用
    Linux下安装Tomcat
    Linux安装MySQL
    jquery的clone方法bug的修复select,textarea的值丢失
    sql 跨服务器查询数据
    无法执行该操作,因为链接服务器 "xxxxx" 的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务
    web服务器决定支持多少人同时在线的因素
    2016最新的中国省市区三级数据库表.sql mssql
    sqlserver2008R2数据库自动备份脚本
    sql server 2008 windows验证改混合登陆中SqlServer身份验证用户名密码
  • 原文地址:https://www.cnblogs.com/zhangmingzhao/p/7868421.html
Copyright © 2020-2023  润新知