NodeJS七天课程学习笔记_第7天综合案例
课程内容概要:
1. 介绍path模块的api
2. 重点介绍path.join方法 与 __dirname
3. 介绍xheditor编辑器的使用(包括上传图片)
4. 介绍formidable中间件处理上传的图片
提了一下 编辑器默认的是: 15号字体 因为大小最合适
讲了一下chrome的插件: editthiscookie
不要担心模块重复加载性能问题,因为模块加载是有缓存的
中间件midware 就是一个方法(包装)
提了一下,使用 postman 模拟请求
提了一下 chrome插件: cors toggle
喊了一下口号: 热爱编程,享受生活
推荐了「深入理解ES6」(尼古拉斯·泽卡斯)、「JavaScript高级程序设计」(小孩望远镜)、
总结了MongoDB数据库的特点:
1. 灵活
2. 不用建表
3. 业务的改动不用关心表结构
4. DBA、架构师 都要掌握(设计、维护、分布式计算)
总结了Mongoose的使用方法:
1. 虽然mongodb官方包也可以操作MongoDB数据库,但是...
2. mongoose开发者是 WordPress团队
3. 设计Schema
4. 生成Model(模型构造函数)
5. CRUD (支持Promise.then语法)
总结了Promise的使用方法:
1. 介绍了什么是回调地狱(回调函数中层层嵌套回调函数)
2. ECMAScript6 中新增了一个API: Promise
3. Promise相当于一个容器(同步执行),一旦创建会立即执行里面的代码(通常是异步操作的代码块block)
4. 异步任务 初始状态是pending
5. 最终状态只能是成功(resolve)或者失败(reject)
6. then方法的参数1是成功的结果(resolveCallback)
7. then方法的参数2是失败的结果(rejectCallback)
8. 可以在then方法中返回另一个promise对象,这样就可链式调用then方法
在Node的命令行中,介绍了一下path模块的常用API
如图所示:
介绍一下path路径操作模块
1. path.basename 获取带扩展名的 文件名,如index.html
2. path.dirname 获取目录部分,如"/Users/beyond/sg_node"
3. path.extname 获取扩展名部分,如".html"
4. 强大的path.parse方法,将一个路径转成对象
例如: /Users/beyond/sg_node/index.html
root: "/" 表示 根目录
name: "index" 表示不带后缀的文件名
ext: ".html" 表示后缀名(带点号)
base: "index.html" 表示带后缀的文件名
dir: "/Users/beyond/sg_node" 表示 目录部分
5. 强大的path.join方法
进行多个路径拼接(能智能处理多写或少写 / )
6. path.isAbsolute 判断一个路径是不是绝对路径
7. 强大path.resolve方法,如下图所示
Node中引入自定义模块时的路径标识符就只是相对于当前文件的路径,
与 将来node命令执行时 命令行所在的路径无关!!!
例如:
require('./router')
require('./dao')
这个自定义模块的路径,就只是相对于当前的文件的路径而言的
与 将来node命令执行时 命令行所在的路径无关!!!
区别,注意:
fs.readFile('a.txt')
在readFile读取文件时,这个相对路径,相对的可是将来 Node命令执行时 命令行所在的路径喔~~~
因此,在读写文件时,使用相对路径是不安全的,
因为Node设计为: 读写文件的相对路径只是相对于 Node命令执行时,命令行所在的路径
因此,为了把文件读取时,这个相对路径,转成绝对路径,
我们隆重介绍Node中除了require和exports之外的另外两个非常重要的成员:
__dirname 它可动态获取当前模块所处目录的绝对路径
__filename 它可动态获取当前模块的绝对路径
特别注意:
__dirname和__filename 与 将来node执行时 命令行所在的路径 无关的
当然在把相对路径转换成绝对路径的时候,为了避免手动拼接路径出错,我们推荐使用path.join方法喔~
在开始blog综合案例之前,先讲了一下如何使用path.join(__dirname,'public')生成绝对路径,
以保证任何情况下,目录都是正确路径
node_48的目录情况如下:
示意图就是这样的:
node_48_1.js代码如下:
function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}
// 演示readFile中相对路径 是相对于 node命令执行时,命令行所处的路径
require('./subfolder/node_48_2.js')
node_48_2.js代码如下:
function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}
// 演示readFile中相对路径 是相对于 node命令执行时,命令行所在的路径
fs = require('fs')
// readFile相对路径 不安全, 因为它是相对于 node命令执行时,命令行所在路径
fs.readFile('./node_48_3.txt',function (error,data) {
if (error) {
NSLog('读取失败: ' + error)
}else{
NSLog('读取成功: \n' + data)
}
})
我们先来 正确执行一次 ,即:
1. 将命令行 cd 到subfolder目录中
2. node命令 执行 上一级目录中的node_48_1.js文件
效果如下:
下面,我们直接在node_48目录下执行该目录下的node_48_1.js
由于 node_48_1.js中require进来了子目录subfolder中的node_48_2.js
而node_48_2.js使用相对路径读取的是同级目录subfolder中的node_48_3.txt
但是: readFile中相对路径设计之初就 是 相对于 执行Node命令时,所处路径
而我们这时, 是在node_48目录下 执行的node命令, 而不是 subfolder目录了
因此,报错: 在node_48目录中找不到node_48_3.txt,如图所示:
解决办法如下:
使用Node提供的__dirname和path.join方法 把readFile中的相对路径,改成绝对路径就好了
node_48_2.js代码如下
function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}
// 演示readFile中相对路径 是相对于 node命令执行时,命令行所在的路径
fs = require('fs')
path = require('path')
// readFile相对路径 不安全, 因为它是相对于 node命令执行时,命令行所在路径
// fs.readFile('./node_48_3.txt',function (error,data) {
// 通过 Node提供的__dirname和path.join,将相对路径转成绝对路径
fs.readFile(path.join(__dirname,'./node_48_3.txt'),function (error,data) {
if (error) {
NSLog('读取失败: ' + error)
}else{
NSLog('读取成功: \n' + data)
}
})
这时,无论你在哪个路径下通过node 命令执行 node_48_1.js都能成功读取node_48_3.txt的内容了
效果如下:
下面的node_49.js 简单演示了一下node提供的__dirname和__filename输出结果:
node_49.js代码如下:
function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}
NSLog(__dirname,false)
NSLog(__filename)
(注意: __dirname和__filename
千万不要使用 字符串拼接)
效果如下:
在开始blog正式项目之前,我们还要先讲一下
如何 用使用富文本编辑器xheditor来上传文件
以及 如何使用中间件formidable 处理上传的头像图片
总体效果如下:
先说说xheditor的使用方法
官网:xheditor.com
第1步, 下载(我这儿下载的是1.4M大小的V1.2.2版本)
第2步, 解压
第3步, 拷贝 3个文件夹, 3个js文件 到public/js目录下
表情目录: xheditor_emot
皮肤目录: xheditor_skin
插件目录: xheditor_plugins
jquery文件: jquery1.4.4.js
语言包文件: xheditor-zh-cn.js
核心JS文件: xheditor-1.2.2.min.js
如下图所示
第4步,使用xheditor
这儿我们使用的是node_50_edit.html作为上传页面
步骤1: 严格按顺序 引入public/js目录下的 xheditor 相关的3个js文件
<!-- 第1步. 必须先引入 jquery 1.4.4 -->
<script type="text/javascript" src="public/js/jquery1.4.4.js">
</script>
<!-- 第2步. xheditor的核心JS -->
<script type="text/javascript" src="public/js/xheditor-1.2.2.min.js">
</script>
<!-- 第3步. xheditor 支持中文 -->
<script type="text/javascript" src="public/js/xheditor-zh-cn.js">
</script>
步骤2: 创建表单,里面有一个textarea, id为 id_xheditor (后面要用这个id查找并初始化)
<div style="margin:0 auto;text-align:center;padding-left:50px;padding-right:50px;">
<form method="post" action="xxx.php">
<!-- 第4步. xheditor所使用的id -->
<textarea id="id_xheditor" rows="12" cols="80" style="width: 100%;height:240%;">
未闻花名 vwhm.net
</textarea>
</form>
</div>
步骤3: 在document.ready方法中, 根据textarea的id_xheditor查找,并进行初始化
$(document).ready(function () {
var uploadUrl = "uploadfile"
// 第5步. 图片上传配置
$('#id_xheditor').xheditor({
// 上传图片
upImgUrl: uploadUrl,
// 支持的图片后缀
upImgExt: "jpg,jpeg,gif,png",
// 上传回调函数
onUpload: uploadCompleteFunction,
// 多文件上传
upMultiple: true,
// 默认皮肤
skin: 'default',
// 工具栏样式
tools: 'full',
upLinkUrl:uploadUrl,
upLinkExt:"zip,rar,txt",
upFlashUrl:uploadUrl,
upFlashExt:"swf",
upMediaUrl:uploadUrl,
upMediaExt:"avi,mp4,wmv,flv"
})
})
步骤4: 做做样子,实现一下 上传回调函数(初始化的时候不写回调,那就不实现 也不影响)
// 第6步. 上传回调函数,参数是服务器返回的 图片url(例如:upload/beyond.jpg)
function uploadCompleteFunction (responseMsg) {
NSLog('上传回调: ' + responseMsg)
}
完整的node_50_edit.html代码如下:
<!DOCTPYE html>
<html lang="zh">
<head>
<link rel="icon" href="public/img/beyond.jpg" type="image/x-icon"/>
<meta charset="UTF-8">
<meta name="author" content="beyond">
<meta http-equiv="refresh" content="520">
<meta name="description" content="未闻花名-免费零基础教程-beyond">
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" />
<meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,汇编,日语,英语,泰语,韩语,俄语,粤语,阿语,魔方,乐理,动漫,PR,PS,AI,AE">
<title>beyond心中の动漫神作</title>
<link rel="stylesheet" type="text/css" href="public/css/beyondbasestylewhite5.css">
<script type="text/javascript" src="public/js/nslog.js"></script>
<!--[if lt IE 9]>
<script src="//apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script>
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.js">
</script>
<![endif]-->
<style type="text/css">
body{
font-size: 100%;
/*声明margin和padding是个好习惯*/
margin: 0;
padding: 0;
background-image: url("public/img/sakura4.png");
background-repeat: no-repeat;
background-position: center center;
}
</style>
<!-- 绿色按钮的css效果 -->
<link rel="stylesheet" type="text/css" href="public/css/beyondbuttongreen.css">
<!-- 第1步. 必须先引入 jquery 1.4.4 -->
<script type="text/javascript" src="public/js/jquery1.4.4.js">
</script>
<!-- 第2步. xheditor的核心JS -->
<script type="text/javascript" src="public/js/xheditor-1.2.2.min.js">
</script>
<!-- 第3步. xheditor 支持中文 -->
<script type="text/javascript" src="public/js/xheditor-zh-cn.js">
</script>
</head>
<body>
<h1 style="color:white;text-shadow:2px 2px 4px #000;letter-spacing:5px;" class="sgcontentcolor sgcenter">
未闻花名
</h1>
<div style="margin:0 auto;text-align:center;padding-left:50px;padding-right:50px;">
<form method="post" action="xxx.php">
<!-- 第4步. xheditor所使用的id -->
<textarea id="id_xheditor" rows="12" cols="80" style="width: 100%;height:240%;">
未闻花名 vwhm.net
</textarea>
</form>
</div>
<p class="sgcenter">
<b>注意: </b>NodeJS + formidable中间件 + xheditor编辑器
</p>
<footer id="copyright">
<p style="font-size:14px;text-align:center;font-style:italic;">
Copyright © <a id="author">2018</a> Powered by <a id="author">beyond</a>
</p>
</footer>
<script type="text/javascript">
/*
重要说明:
1,上传文件域的名字 必须为:filedata
2,返回结构必需为json,并且结构必须如下:
完整的图片url是 http://localhost:5267/upload/beyond.jpg
{"err":"","msg":"upload/beyond.jpg"}
若上传出现错误,请将错误内容保存在err变量中;
若上传成功,请将服务器上的绝对或者相对地址保存在msg变量中。
编辑器若发现返回的err变量不为空,则会弹出窗口显示返回的错误内容
*/
$(document).ready(function () {
var uploadUrl = "uploadfile"
// 第5步. 图片上传配置
$('#id_xheditor').xheditor({
// 上传图片
upImgUrl: uploadUrl,
// 支持的图片后缀
upImgExt: "jpg,jpeg,gif,png",
// 上传回调函数
onUpload: uploadCompleteFunction,
// 多文件上传
upMultiple: true,
// 默认皮肤
skin: 'default',
// 工具栏样式
tools: 'full',
upLinkUrl:uploadUrl,
upLinkExt:"zip,rar,txt",
upFlashUrl:uploadUrl,
upFlashExt:"swf",
upMediaUrl:uploadUrl,
upMediaExt:"avi,mp4,wmv,flv"
})
})
// 第6步. 上传回调函数 (初始化的时候不写回调,那就不实现 也不影响)
// 参数是服务器返回的 图片url(例如:upload/beyond.jpg)
function uploadCompleteFunction (responseMsg) {
NSLog('上传回调: ' + responseMsg)
}
</script>
</body>
</html>
说完了xheditor的使用方法,接下来说说如何使用用来处理上传文件的 中间件 formidable
官网的使用文档: npmjs.com/package/formidable#readme
其他的几个也可以实现表单中上传文件的解析
第1步, 安装formidable:
npm install formidable --save
第2步, 配置
// ---------------使用formidable解析上传的图片--------------------
var formidable = require('formidable')
// var util = require('util') // 只是调试用
var path = require('path')
第3步, 使用
重要说明:
重要说明:
1,上传文件域的名字 必须为:filedata
2,返回结构必需为json,并且结构必须如下:
// 完整的图片url是 http://localhost:5267/upload/beyond.jpg
{"err":"","msg":"upload/beyond.jpg"}若上传出现错误,请将错误内容保存在err变量中;
若上传成功,请将服务器上的绝对或者相对地址保存在msg变量中。
编辑器若发现返回的err变量不为空,则会弹出窗口显示返回的错误内容
// ----------------上传一张图片-------------------
router.post('/uploadfile',function (request,response) {
// 使用formidable中间件
var form = new formidable.IncomingForm();
// 配置 上传保存路径 (应该将日期计算进来)
form.uploadDir = '/Users/beyond/sg_node/node_27/uploads'
// 让formidable中间件 解析上传的图片
form.parse(request,function (error,fields,files) {
// var uploadObj = util.inspect({
// fields: fields,
// files: files
// })
// 保存的完整路径
var uploadSavePath = files['file']['path']
var pathObj = path.parse(uploadSavePath)
// 文件名,不带后缀
var filePlainName = pathObj.name
// 回写给xheditor用的成功的json,格式必须这样写
// {"err":"","msg":"uploads/beyond.jpg"}
var jsonObj = {
err: "",
msg: 'uploads/' + filePlainName
}
// 回写给浏览器
response.writeHead(200, {'content-type': 'text/json'});
response.end(JSON.stringify(jsonObj));
})
})
node_50_index.js这个APP入口文件完整的代码如下:
function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}
// 导入框架
var express = require('express')
var path = require('path')
// 创建服务器对象
var appServer = express()
// 监听端口,并启动服务
appServer.listen(5267,function (error) {
if (error) {
return NSLog('启动失败: ' + error)
}
NSLog('服务启动成功')
})
// -----------------------------------
// 静态资源请求时的 staticFileUrlPrefix
var staticFileUrlPrefix = '/public/'
// var staticFileUrlPrefix = '/public'
// 访问也只能使用 localhost:5267/public/img/beyond.jpg
// 磁盘上的静态资源目录
var staticFilePath = './public/'
// var staticFilePath = 'public'
var callbackFunction = express.static(staticFilePath)
appServer.use(staticFileUrlPrefix,callbackFunction)
// 再开一个静态资源目录
appServer.use('/uploads/',express.static(path.join(__dirname,'uploads')))
// -----------------------------------
// 指明:对于 所有后缀为html 的模板文件 使用模板引擎
var templateFileSuffix = 'html'
appServer.engine(templateFileSuffix,require('express-art-template'))
// 下面这一句参数配置,可有可无
appServer.set('view options',{
debug: process.env.NODE_ENV !== 'production'
})
// 注意:如果不想把模板文件放在默认的views目录下,则可以通过下面代码更改设置
// appServer.set('views','其他目录')
// -----------------------------------
// 使用middleware中间件body-parser进行post请求体中数据解析
var bodyParser = require('body-parser')
// 设置解析 application/x-www-form-urlencoded
appServer.use(bodyParser.urlencoded({extended: false}))
// 设置解析 application/json
appServer.use(bodyParser.json())
// -----------------------------------
// 自定义路由设计的目的是:
// 1.让主入口程序的职责更加单一,代码更加简洁
// 1.1 创建服务
// 1.2 做一些服务相关的配置,比如:
// 1.2.1 静态资源配置
// 1.2.2 模板引擎配置
// 1.2.3 body-parse 解析表单
// 1.2.4 挂载自定义路由
// 1.2.5 监听端口,启动服务
// 使用自定义的路由模块 必须使用./
// 注意: 配置模板引擎和body-parser, 一定要在挂载路由之前
var beyondRouter = require('./node_50_router')
appServer.use(beyondRouter)
node_50_router.js这个路由文件完整的代码如下:
function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};
/*
自定义路由模块的职责是:
专门处理所有的路由
根据不同的请求方式和路径,采取相应的处理方法
*/
// express 专门提供了路由的处理方法
var express = require('express')
// ---------------使用formidable解析上传的图片--------------------
var formidable = require('formidable')
// var util = require('util')
var path = require('path')
// -----------------------------------
// 1.使用express专门提供的路由器处理路由
var router = express.Router()
// -----------------------------------
// 时间格式化
// var BeyondDateFormatFunction = require('./BeyondDateFormat')
// ----------------首页-------------------
router.get('/',function (request,response) {
response.render('index/node_50_edit.html')
})
// ----------------上传一张图片-------------------
router.post('/uploadfile',function (request,response) {
// 使用formidable中间件
var form = new formidable.IncomingForm();
// 配置 上传保存路径 (应该将日期计算进来)
form.uploadDir = '/Users/beyond/sg_node/node_27/uploads'
// 让formidable中间件 解析上传的图片
form.parse(request,function (error,fields,files) {
// var uploadObj = util.inspect({
// fields: fields,
// files: files
// })
// 保存的完整路径
var uploadSavePath = files['file']['path']
var pathObj = path.parse(uploadSavePath)
// 文件名,不带后缀
var filePlainName = pathObj.name
// 回写给xheditor用的成功的json,格式必须这样写
// {"err":"","msg":"uploads/beyond.jpg"}
var jsonObj = {
err: "",
msg: 'uploads/' + filePlainName
}
// 回写给浏览器
response.writeHead(200, {'content-type': 'text/json'});
response.end(JSON.stringify(jsonObj));
})
})
// 3.在模块文件最后,导出router
module.exports = router
整个NodeJS + formidable中间件 + xheditor上传图片的效果如下:
明天开始正式的blog综合项目
未完待续,下一章节,つづく