- 注意: 撰寫本文目的主要是為了給自己做一個備忘錄巾腕,如果你學(xué)過Node.js并且希望從本文中找到一些忘記的知識點豫领,那么你可以閱讀本文章纪隙。由于文章內(nèi)講解并不是很多,因此此文章并不適合小白入門使用碗硬。
1.項目簡介
- 這個項目是我跟著視頻學(xué)習(xí)Node.js時跟著老師做的小項目瓤湘,現(xiàn)在拿出來與讀者分享一下,正好練習(xí)一下前面學(xué)過的知識恩尾。
- 我們將要實現(xiàn)的是一個小小相冊弛说。項目描述:有三個相冊,我們可以查看相冊里的圖片翰意,并且可以往相冊里面上傳圖片木人。
- 在項目中我們主要使用的是express模塊以及ejs來完成的。
- 在項目中猎物,我們使用了模塊化管理虎囚,文件操作模塊也放在了單獨的文件夾中,路由也單獨由一個文件管理并向外暴露接口蔫磨。
主頁頁面展示:
相冊詳情頁面展示:
訪問錯誤頁面:
目錄結(jié)構(gòu):
2.代碼展示
2.1.app.js
- app.js是一個Node項目的核心文件淘讥,它主要是使用中間接對請求進行處理,并且將各請求所需要執(zhí)行的功能分發(fā)給相應(yīng)的文件進行執(zhí)行堤如。
app.js
var express = require("express");
var app = express();
//package.json中main默認是index.js
// "main" : "router.js" 設(shè)置使得app.js中的router引入室不需要再controller后面加上/router.js
var router = require("./controller");
//設(shè)置模板引擎
app.set("view engine","ejs");
//路由中間件
//靜態(tài)頁面
app.use(express.static("./public"));
app.use(express.static("./uploads"));
//首頁
app.get("/",router.showIndex); //get請求回味回調(diào)函數(shù)showIndex自動加上req蒲列、res參數(shù)
app.get("/:albumName",router.showAlbum);
app.get("/up",router.showUp);
app.post("/up",router.doPost);
//404最后的中間件
app.use(function (req,res) {
res.render("err",{
"baseurl" : req.pathname
})
})
app.listen(3000);
2.2.view模塊
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">
<!-- 上述3個meta標(biāo)簽*必須*放在最前面,任何其他內(nèi)容都*必須*跟隨其后搀罢! -->
<title>小小相冊</title>
<!--<link href="/</%= baseurl /%/>/css/bootstrap.min.css" rel="stylesheet">-->
<link href="/css/bootstrap.min.css" rel="stylesheet">
<!-- /就表示根目錄蝗岖,沒有必要傳值得到根目錄路徑 -->
</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>
<ol class="breadcrumb">
<li><a href="/">全部相冊</a></li>
<li class="active"><%= albumname %></li>
</ol>
<div class="container">
<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>
</div>
<% } %>
</div>
</div>
<script src="/js/jQuery.js"></script>
<script src="/js/bootstrap.min.js"></script>
</body>
</html>
err.ejs
<!--已省略部分代碼-->
<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="/images/404.jpg">
</div>
index.ejs
<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/file.jpg" alt="...">
</a>
<h4><%= albums[i] %></h4>
</div>
<% } %>
</div>
</div>
up.ejs
<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">
<div class="row">
<form style="width: 40%;" 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">
</div>
<button type="submit" class="btn btn-default">上傳</button>
</form>
</div>
</div>
2.2.路由模塊
package.json
{
"main" : "router.js"
}
router.js
- 其實這個路由文件中存儲的是沒一個路由執(zhí)行所需要調(diào)用的方法,這些方法以暴露接口的方式供外部調(diào)用榔至,每個方法執(zhí)行特定的功能抵赢。
- router.js中調(diào)用了以下幾個模塊--formidable、util、fs铅鲤、path划提、date-time模塊,同時引用了部分其他文件邢享。
var file = require("../modejs/file.js");
var formidable = require('formidable');
var util= require("util");
var fs = require("fs");
var path = require("path");
var dateTime = require("date-time");
//首頁
exports.showIndex = function (req,res) {
//傳統(tǒng)思維鹏往,不是nodejs異步的思維方式
//這種方法會造成還沒有獲取到數(shù)據(jù)就把值傳過去了,異步執(zhí)行
// res.render("index",{
// "albums" : file.getAllAlbums()
// });
//這就是Node.js的編程思維,所有的東西都是異步的
//所以內(nèi)層函數(shù)不是return回來東西,而是調(diào)用高層函數(shù)提供的回調(diào)函數(shù)骇塘,把數(shù)據(jù)當(dāng)做回調(diào)函數(shù)的參數(shù)使用
file.getAllAlbums(function (err,allAlbums) {
if(err){
res.send(err);
return;
}
res.render("index",{ //向靜態(tài)頁面(index.ejs)傳輸數(shù)據(jù)并顯示index.ejs頁面
"albums" : allAlbums
})
})
}
exports.showAlbum = function (req,res,next) {
//遍歷相冊中的所有圖片
var albumName = req.params.albumName;
//具體業(yè)務(wù)交給model
file.getAllImagesByAlbumName(albumName,function (err,imagesArray) {
if(err){
// res.send(err);
next();
return;
}
res.render("album",{
"albumname" : albumName,
"images" : imagesArray
})
})
}
//顯示上傳
exports.showUp = function (req,res) {
file.getAllAlbums(function (err,allAblums) {
if(err){
res.send(err);
return;
}
res.render("up",{
"albums" : allAblums
})
})
}
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 > 2048){
// res.send("圖片大小應(yīng)該小于2M");
// //刪除圖片
// fs.unlink(files.tupian.path,function (err) {
// if (err){
// res.send(err);
// return;
// }
// });
// return;
// }
var time = dateTime(); //date-time模塊函數(shù) //目前這個時間有毒伊履,有非法字符
var ran = parseInt(Math.random() * 89999 + 10000); //5位隨機數(shù)
var extname = path.extname(files.tupian.name); //取文件后綴名
var wenjianjia = fields.wenjianjia;
var oldpath = files.tupian.path;
var newpath = path.normalize(__dirname + "/../uploads/" + wenjianjia + "/" + ran + extname);
fs.rename(oldpath,newpath,function (err) {
if (err){
throw Error("改名失敗");
return;
}
res.end("成功");
});
});
}
2.3.文件操作模塊
- 文件操作模塊實現(xiàn)了對文件進行操作的方法,以供router.js等文件調(diào)用款违。
var fs = require("fs");
//這個函數(shù)的callback中含有兩個參數(shù)唐瀑,一個是err
//另一個是存放所有文件夾名稱的array
exports.getAllAlbums = function (callback) {
fs.readdir("./uploads",function (err,files) {
var allAlbums = [];
if(err){
callback("沒有找到uploads文件夾",null)
}
(function iterator(i) {
if(i == files.length){
//遍歷結(jié)束
console.log(allAlbums);
//我們現(xiàn)在集中精力,找到所有文件夾
callback(null,allAlbums);
return;
}
fs.stat("./uploads/" + files[i],function (err,stats) {
if(err){
callback("找不到文件" + files[i],null);
return;
}
if(stats.isDirectory()){
allAlbums.push(files[i]);
}
iterator(i + 1);
})
})(0)
})
}
//通過文件名得到所有圖片
exports.getAllImagesByAlbumName = function (albumName,callback) {
fs.readdir("./uploads/" + albumName,function (err,images) {
var allImages = [];
if(err){
callback("沒有找到uploads文件夾",null);
return;
}
(function iterator(i) {
if(i == images.length){
//遍歷結(jié)束
console.log(allImages);
//我們現(xiàn)在集中精力奠货,找到所有文件夾
callback(null,allImages);
return;
}
fs.stat("./uploads/" + albumName + "/" + images[i],function (err,stats) {
if(err){
callback("找不到文件" + images[i],null);
return;
}
if(stats.isFile()){
allImages.push(images[i]);
}
iterator(i + 1);
})
})(0)
})
}
文集推薦:
Java基礎(chǔ)方法集1
Python基礎(chǔ)知識完整版
Spring Boot學(xué)習(xí)筆記
Linux指令進階
Java高并發(fā)編程
SpringMVC基礎(chǔ)知識進階
Mysql基礎(chǔ)知識完整版
健康管理系統(tǒng)學(xué)習(xí)花絮(學(xué)習(xí)記錄)
Node.js基礎(chǔ)知識(隨手筆記)
MongoDB基礎(chǔ)知識
Dubbo學(xué)習(xí)筆記
Vue學(xué)習(xí)筆記(隨手筆記)
聲明:發(fā)表此文是出于傳遞更多信息之目的介褥。若有來源標(biāo)注錯誤或侵犯了您的合法權(quán)益,請作者持權(quán)屬證明與本我們(QQ:981086665递惋;郵箱:981086665@qq.com)聯(lián)系聯(lián)系柔滔,我們將及時更正、刪除萍虽,謝謝睛廊。