摘要:通过前两天的学习我大概学了了,用 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
用 express 静态出 public 和 uploads 文件夹,用来放资源文件,然后分别路由主页,相册文件夹,上传页面,上传表单处理。然后在控制层的 controller 来控制前台和后台的交互
- //首页 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);
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",{
- //注意这里异步的,遇到阻塞,会直接呈递模版引擎,所以这种写法是错误的,小函数会没执行完,就呈递
底层的真正处理的模型层的 file.js,注意的是由于这里没用 es6 的先进写法,所以很多是异步语句,正常的 return 返回是不行的,需要递归迭代来获得所有数据,用 callback 回调处理
- // "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
- 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
相册页:album.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="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>
上传页: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">
- <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>
<!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>
来源: https://www.cnblogs.com/15fj/p/8116508.html