热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

用node.js实现mvc相册资源管理器

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

摘要:通过前两天的学习我大概学了了,用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) ;
//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) {
    //错误的:传统的思维不是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=">
    <link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
    <style>
        .row h4{
            text-align: center;
        }
    style>
head>
<body>

<nav class="navbar navbar-default">
    <div class="container-fluid">
        
        <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 navigationspan>
                <span class="icon-bar">span>
                <span class="icon-bar">span>
                <span class="icon-bar">span>
            button>
            <a class="navbar-brand" href="#">小小相册a>
        div>

        
        <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>
    div>
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>

 

相册页: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=">
    <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">
        
        <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 navigationspan>
                <span class="icon-bar">span>
                <span class="icon-bar">span>
                <span class="icon-bar">span>
            button>
            <a class="navbar-brand" href="#">小小相册a>
        div>

        
        <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>
    div>
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=">
    <link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
    <style>
        .row h4{
            text-align: center;
        }
    style>
head>
<body>

<nav class="navbar navbar-default">
    <div class="container-fluid">
        
        <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 navigationspan>
                <span class="icon-bar">span>
                <span class="icon-bar">span>
                <span class="icon-bar">span>
            button>
            <a class="navbar-brand" href="#">小小相册a>
        div>

        
        <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>
    div>
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">Submitbutton>
        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=">
    <link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
    <style>
        .row h4{
            text-align: center;
        }
    style>
head>
<body>

<nav class="navbar navbar-default">
    <div class="container-fluid">
        
        <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 navigationspan>
                <span class="icon-bar">span>
                <span class="icon-bar">span>
                <span class="icon-bar">span>
            button>
            <a class="navbar-brand" href="#">小小相册a>
        div>

        
        <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>
    div>
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>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

 


推荐阅读
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • Node.js学习笔记(一)package.json及cnpm
    本文介绍了Node.js中包的概念,以及如何使用包来统一管理具有相互依赖关系的模块。同时还介绍了NPM(Node Package Manager)的基本介绍和使用方法,以及如何通过NPM下载第三方模块。 ... [详细]
  • express工程中的json调用方法
    本文介绍了在express工程中如何调用json数据,包括建立app.js文件、创建数据接口以及获取全部数据和typeid为1的数据的方法。 ... [详细]
  • node.jsrequire和ES6导入导出的区别原 ... [详细]
  • ps:写的第一个,不足之处,欢迎拍砖---只是想用自己的方法一步步去实现一些框架看似高大上的小功能(比如说模型中的toArraytoJsonsetAtt ... [详细]
  • 我尝试使用Vue.js在Laravel中实现imageupload吗?但是,我不知道为什么图像 ... [详细]
  • 用ESP32与Python实现物联网(IoT)火焰检测报警系统
    下图是本案例除硬件连线外的3步导学开发过程,每个步骤中实现的功能请参考图中的说明。在硬件连线完成之后我们建议您先使用“一分钟上云体验”功能预先体验本案例的实际运行效果 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • JavaScript简介及语言特点
    本文介绍了JavaScript的起源和发展历程,以及其在前端验证和服务器端开发中的应用。同时,还介绍了ECMAScript标准、DOM对象和BOM对象的作用及特点。最后,对JavaScript作为解释型语言和编译型语言的区别进行了说明。 ... [详细]
author-avatar
0704034铜豌豆
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有