学习node第一阶段##
创建helloWord文件
//require表示引包,引包就是引用自己的一个特殊功能
var http = require('http');
//创建服务器,参数是一个回调函数,表示如果有请求过来,是做什么
http.createServer(function(req, res){
//reg表示请求,request;res表示响应,response
//设置HTTP图片头部,状态码是200,文件类型是html,字符集是UTF-8
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<h1>Node.js</h1>');
res.end('<p>Hello world</p>');
}).listen(3000);
//运行服务器,监听3000端口(端口号可以任改)
console.log("HTTP server is listening at port 3000.");
小技巧:
- cmd运行文件时,可以直接拖文件,也可以cmd自己感应到文件的路径
>node c:/.........
- 推荐不用完整文件名,需要先进入路径
- node.js是运行在服务器上的,返回客户端以后,就是纯HTML
var http = require('http');
http.createServer(function(req, res){
res.end("sss" + (1 + 2 + 3));
//得到sss6
res.end("sss" + 1 + 2 + 3);
//得到sss123
}).listen(3000);
js没有web容器的概念
- node.js文件没有文件夹,没有根目录,也就是不能直接将html和Node.js存在一个m目录下就能直接进入网站运行html,需要加入文件流,进行if else的判断加入url使得其进入某个html文件中。
//require表示引包,引包就是引用自己的一个特殊功能
var http = require('http');
//引入文件包
var fs = require('fs');
http.createServer(function(req, res){
//利用判断语句进行分析进入哪个html文件
if(req.url == "/test1"){
//通过fs包读取文件,并将文件的内容通过data传给end
fs.readFile("./test1.html",function(err,data){
res.writeHead(200, {'Content-Type': 'text/html;charset = UTF-8'});
res.end(data);
})
}else if(req.url == "/test2"){
fs.readFile("./test2.html",function(err,data){
res.writeHead(200, {'Content-Type': 'text/html;charset = UTF-8'});
res.end(data);
})
}else {
//此时状态码为400,为错误error页面
res.writeHead(400, {'Content-Type': 'text/html;charset = UTF-8'});
res.end("嘻嘻没有这个页面哦");
}
}).listen(3000);
console.log("HTTP server is listening at port 3000.");
- 就算把图片与node.js,html放在一个根目录下,直接将html里面加入img标签,也无法获取图片,因为在服务器运行,js没有web 的概念。
- 首先,在相应的html上加img标签,再在js中载入判断url语句,读取Img文件,将其加入服务器中。此时,对应html的服务器文件也可以访问到图片。
if(req.url == "/01.png"){
fs.readFile("./01.png",function(err,data){
//此时type为image
res.writeHead(200, {'Content-Type': 'image/png'});
res.end(data);
})
}
- 加入css文件也是一样,需要用if else语句将它加到服务器中;其中content-type为text/css.与上面同理。
- 其次,if else里面readFile的路径为相对于cmd里面>前面的路径而不是相对于node.js的,所以,进入cmd命令后,首先将地址cd成装文件的文件夹的地址。
http模块简单讲解
- 将服务器包引入:require(‘http’);
具体见代码区
//require引入一个http模块
var http = require('http');
//创建一个服务器,function表示回调后要做的事情
http.createServer(function(req, res){
//req表示请求,res表示响应
res.writeHead(200, {'Content-Type': 'text/html;charset = UTF-8'});
//为一个必须要存在的代码,表示全部请求已经发送,若没有这一句则无法再服务器运行
res.end("hahahahhaahah");
}).listen(3000);//监听端口
console.log("HTTP server is listening at port 3000.");
- res.write()就是输出语句
- write与end必须为字符串输出 (1+2+3).toString();
- end后面不能在写语句了
- res.setHeader(“Content-Type”,“text-html”);相当于writeHead();
url模块
- url模块可以将请求的地址常见的位置不用正则表达式可以将他们分开。
- url.format可以将对象转成字符串
var http = require('http');
//引入url模块
var url = require('url');
http.createServer(function(req, res){
//url.parse()可以将url分为很多部分
//host、href、port、path、pathname、query、hash、protocol、search、username
var pathname = url.parse(req.url).pathname;
var href = url.parse(req.url).href;
var port = url.parse(req.url).port;
var path = url.parse(req.url).path;
var query = url.parse(req.url,true).query;
//true为使得参数为一个一个打点
var age = query.age;
var search = url.parse(req.url).search;
console.log("pathname:" + pathname);
console.log("href:" + href);
console.log("port:" + port);
console.log("path:" + path);
console.log("age:" + age);
console.log("search:" + search);
res.end();
}).listen(3000);//监听端口
- queryString是查询字符串,他的功能被url包含
- parse(str)将字符串转成对象
- parse(str,AAA)AAA为一个字符串编码的设置
- querystring.parse(‘w=%D6%D0%CE%C4&foo=bar’, null, null,
{ decodeURIComponent: gbkDecodeURIComponent }); //为一个中文的编码
- querystring.parse(‘w=%D6%D0%CE%C4&foo=bar’, null, null,
- stringify(aa)将aa对象转化为字符串
--------------------------------------表单事件和简单的路由查询事件见网盘---------------------------------------
事件环机制
- 引入fs模块:require(‘fs’);
fs模块
- 注意console.log()的顺序以及次数,3次是因为css也是文件算一次,favicon算一次,html算一次
var http = require('http');
//引入url模块
var fs = require('fs');
http.createServer(function(req, res){
//读取文件,./表示当前目录,一定要加进去
fs.readFile("./test1.html",{"charset":"UTF-8"},function(err,data){
if(err){
throw err;
}
console.log(1);
res.end(data);
});
console.log(2);
// fs.mkdir("./album/aaa");
}).listen(3000);//监听端口s
-
- 加入以下代码,则不会将favicon.ico的返回去。
if(req.url == "/favicon.ico") {
return;
}
-
fs.mkdir(path,callback);创建文件夹;fs.rmdir(path);消除文件夹
-
fs.readdir(path,function(err,files){})读目录里面所有的文件,将文件名存入数组中
-
fs.stat(path,function(err,data){})检测文件的状态,看他是一个什么样的文件
//检测文件状态是什么文件
fs.stat("./album/bbb.txt",function(err,data){
//检测aaa是否是一个文件夹,返回boolean值
console.log(data.isDirectory());
//检测是否为一个文件夹
console.log(data.isFile());
//检测是否为一个文件
});
- fs.readdir(path,function(err,files){
})可以遍历path内的所有文件内容,
//读取目录里面的所有文件,包括文件夹,文件,图片
// filses是一个所有文件名的一个数组,并不是一个文件的数组
fs.readdir("./album",function(err,files){
console.log(files);
//此时将其数组变成一个一个字符串遍历
for (var i = 0; i < files.length; i++) {
var fileName = files[i];
fs.stat("./album/" + fileName,function(err,data){
console.log(fileName + ":" + data.isFile());
});
}
});
-
但此时会发现输出全为bbb.txt文件内容,因为他是异步的,在aaa还没有执行完之后,就进行了bbb的检测。
-
如果将是文件的内容加到数组里面去,但是数组面一直是bbb
var wenjianjia = [];
fs.readdir("./album",function(err,files){
console.log(files);
//此时将其数组变成一个一个字符串遍历
for (var i = 0; i < files.length; i++) {
var fileName = files[i];
fs.stat("./album/" + fileName,function(err,data){
console.log(fileName + ":" + data.isFile());
//由于异步的关系,在执行判断之前就console.log出去了
if(data.isFile()) {
wenjianjia.push(fileName);
}
console.log(wenjianjia);
});
}
});
把异步变成同步
- 加入立即执行函数,利用这个迭代函数,在 i = 0执行完以后再次执行i = 1的功能,强制转换为同步。
fs.readdir("./album",function(err,files){
var wenjianjia = [];
(function iterator(i) {
if(i == files.length) {
console.log(wenjianjia);
return;
}
fs.stat("./album/" + files[i],function(err,data) {
if(data.isFile()) {
wenjianjia.push(files[i]);
}
iterator(i + 1);
});
})(0);
静态资源管理文件
- 在文件夹中加入static文件夹,里面保存先关文件,手动在代码中加入执行语句,即在req中同阿帕奇加入文件的名字后直接执行这个文件。也就是说利用url的parse进行pathname分割,此时再调用fs的readFile的命令,进行读取pathname的文件。同时可以将“/”设置为直接进入Index主页面的方式。当找不到文件时,就直接进入404页面,并将头部设置为404。
var http = require("http");
var fs = require('fs');
var url = require('url');
http.createServer(function (req, res) {
//得到用户的路径
var pathname = url.parse(req.url).pathname;
//如果只有/则让页面进入index主页面
if(pathname = "/") {
fs.readFile("./static/index.html", function(err, data) {
res.end(data);
});
}
//真的读取这个路径的文件
fs.readFile("./static/" + pathname, function (err, data) {
if (err) {
//如果不存在这个页面,就进入404页面
fs.readFile("./static/404.html", function(err, data) {
res.writeHead(404,{"Content-type":"text/html;charset:UTF8"});
res.end(data);
});
//注意一定要返回,否则会执行两次end语句
return;
}
res.end(data);
});
}).listen(3000);
-
但是有一个问题,就是当访问扩展名为非html文件时,就不会返回content-type,在浏览器中会给性能带来干扰。于是就必须加入path模块,引用extname
-
并且运用一个函数将获取的扩展名返回为一个content-type.
var http = require("http");
var fs = require('fs');
var url = require('url');
var path = require('path');
http.createServer(function (req, res) {
//得到用户的路径
var pathname = url.parse(req.url).pathname;
//如果只有/则让页面进入index主页面
if(pathname == "/") {
fs.readFile("./static/index.html", function(err, data) {
res.end(data);
});
}
//读取扩展名
var extname = path.extname(pathname);
//真的读取这个路径的文件
fs.readFile("./static/" + pathname, function (err, data) {
if (err) {
//如果不存在这个页面,就进入404页面
fs.readFile("./static/404.html", function(err, data) {
res.writeHead(404,{"Content-type":"text/html;charset:UTF8"});
res.end(data);
});
//注意一定要返回,否则会执行两次end语句
return;
}
//利用函数GetMime()获取Type类型
var mime = getMime(extname);
res.writeHead(200, {"Content-type":mime});
res.end(data);
});
}).listen(3000);
function getMime (extname) {
switch(extname) {
case ".html":
return "text/html";
break;
case ".jpg":
return "image/jpg";
}
}
学习Node第二阶段
复习1
- 服务器开发注重的是数据,路由。
- node为单线程,必须有非阻塞的I/O
- 一个人io结束了,就用事件环排队用回调函数
- node没有自己的语言,用V8 的引擎,并且大多数都是异步的
- 并且没有web容器根目录
- 系统中默认端口为80
复习2
- 将扩展名的JSON文件导入Js
var http = require("http");
var fs = require('fs');
var url = require('url');
var path = require('path');
http.createServer(function (req, res) {
//得到用户的路径
var pathname = url.parse(req.url).pathname;
//如果只有/则让页面进入index主页面
if(pathname == "/") {
fs.readFile("./static/index.html", function(err, data) {
res.end(data);
});
}
// if(pathname.indexOf(".") == -1) {
// pathname = "/index.html";
// }
//读取扩展名
var extname = path.extname(pathname);
//真的读取这个路径的文件
fs.readFile("./static/" + pathname, function (err, data) {
if (err) {
//如果不存在这个页面,就进入404页面
fs.readFile("./static/404.html", function(err, data) {
res.writeHead(404,{"Content-type":"text/html;charset:UTF8"});
res.end(data);
});
//注意一定要返回,否则会执行两次end语句
return;
}
// 利用函数GetMime()获取Type类型
// getMime(extname,function(mime) {
// res.writeHead(200, {"Content-type":mime});
// res.end(data);
// });
var Mime = getMime(extname);
res.writeHead(200, {"Content-type":Mime});
res.end(data);
});
}).listen(3000);
function getMime (extname) {
fs.readFile("./mime.json", function(err, data) {
if(err) {
throw Error("找不到JSON文件");
}
var ext = JSON.parse(data);
// var mime = ext[extname] || "text/plain"
// callback(mime);
return ext[extname];
});
}
- 但是此时会造成异步,因为读取文件会耗时,导致函数执行的慢
var http = require("http");
var fs = require('fs');
var url = require('url');
var path = require('path');
http.createServer(function (req, res) {
//得到用户的路径
var pathname = url.parse(req.url).pathname;
//如果只有/则让页面进入index主页面
if(pathname == "/") {
fs.readFile("./static/index.html", function(err, data) {
res.end(data);
});
}
// if(pathname.indexOf(".") == -1) {
// pathname = "/index.html";
// }
//读取扩展名
var extname = path.extname(pathname);
//真的读取这个路径的文件
fs.readFile("./static/" + pathname, function (err, data) {
if (err) {
//如果不存在这个页面,就进入404页面
fs.readFile("./static/404.html", function(err, data) {
res.writeHead(404,{"Content-type":"text/html;charset:UTF8"});
res.end(data);
});
//注意一定要返回,否则会执行两次end语句
return;
}
// 利用函数GetMime()获取Type类型
getMime(extname,function(mime) {
res.writeHead(200, {"Content-type":mime});
res.end(data);
});
// var Mime = getMime(extname);
// res.writeHead(200, {"Content-type":Mime});
// res.end(data);
});
}).listen(3000);
function getMime (extname) {
fs.readFile("./mime.json", function(err, data) {
if(err) {
throw Error("找不到JSON文件");
}
var ext = JSON.parse(data);
var mime = ext[extname] || "text/plain"
callback(mime);
// return ext[extname];
});
}
- 利用回调函数将其变成同步。
模块的概念
-
node中以功能划分了很多模块,这时可以将程序划分为不同的部分
-
不能用JS写一个项目,必须要用到MVC
-
不同的js为一个个不同的文件,可以相互require模块,并且只需要require一次,添加了顶层变量。
- 在一个js文件调用到另一个,需要require文件名,并且require的文件也需要将导出的变量或者函数进行exports暴露
foo.js
var msg = "你好";
var info = "hello";
function test () {
console.log(info);
}
//暴露变量以及函数
exports.msg = msg;
exports.info = info;
exports.test = test;
- 可以用module.export = 构造函数,应用文件的类
people.js
function People(name, age) {
this.name = name;
this.age = age;
}
People.prototype = {
sayHello: function(){
console.log("hello");
}
}
//把People暴露出去
module.exports = People;
module.js
var people = require("./People.js");
var xiaoming = new People("xiaoming",13);
xiaomng.sayHello();
- 如果导入类的Js文件的话,就把顶层变量设置为自己接下来想要new的类名
文件夹模块以及package模块
- 凡是读取文件,都必须加./,否则,都默认为node_modules文件夹的内容文件,并且不一定放在一个文件夹中,但必须放在同个磁盘的上面的一层中,因为会逐层去找这个文件夹,但不可以放在其他的磁盘或者同一磁盘的其他文件夹下面。
app.js
/**
* Created with JetBrains WebStorm.
* User: apple
* Date: 17-11-25
* Time: 下午8:22
* To change this template use File | Settings | File Templates.
*/
function People(name, age) {
this.name = name;
this.age = age;
}
People.prototype = {
sayHello: function(){
console.log("hello");
}
}
//把People暴露出去
module.exports = People;
module.js
var People = require("app.js");
var xiaoming = new People("xiaoming",13);
xiaoming.sayHello();
- 或者,将这个文件夹设为node_path的环境变量路径,就可以放在任意位置。这样,分享项目的时候就不必将这个文件夹拷贝过去。
- 若直接require一个不带扩展名的文件,则引用了一个modules文件夹里面的文件夹,而相当于引用了文件夹里面的index.js文件
index.js
/**
* Created with JetBrains WebStorm.
* User: apple
* Date: 17-11-25
* Time: 下午8:28
* To change this template use File | Settings | File Templates.
*/
var info = "hello";
exports.info = info;
module.js
var bar = require("bar");
console.log(bar.info);
- 若moudule下的这个文件夹想要直接引用其他的Js文件,则生成一个package.json文件将main 改为这个文件的文件名,且package.json名字不能改
package.json
{
"main": app.js
}
此时文件夹bar的入口文件为app.js
其中这个json只能放在想要直接引用的这个文件夹下面的根目录下面
npm
- npm就是一个模块下载的一个社区,将模块进行封装供人下载
- www.npmjs.com
npm下载模块的社区地址
- 首先在社区查找想要的功能模块,并将他的API给记录下来。
- 在cmd中,先到工程文件所在位置**npm install …**将他的模块给下载下来,此时中国模块的位置在node_modules文件夹的根目录下面。
- 在所需的Js文件下,进行require("")这个模块,可以直接使用他的模块的函数功能
var sd = require("silly-datetime") ;
var a = sd.format(new Date(), 'YYYYMMMMDDDD');
console.log(a);
-
如果在磁盘根目录进行npm install … ,那么就会在这个磁盘生成一个Node_modules文件夹,将这个模块放在这里面,这样,你的工程文件就找不到这个模块文件了。
-
如果想随时保持更新状态的模块版本,就必须再给模块的Json文件的依赖dependencities这里的版本号全不加,如果是0.1.0,则是使得第一个0固定,若后2 个号改变了,则会持续更新。
-
如果把我们的项目分享给别人的话,不必将这个模块分享给别人,别人可以以自己下载这个模块。
-
在这里的磁盘的工程文件位置这里,cmd 中npm init就会给自己的项目生产package.json文件,这样,在分享自己的项目市,就不需将自己的node_modules文件夹,只需将自己其他的文件与这个json文件给别人,就可以了。
-
如果将自己的的这个依赖都删除,如果在cmd这个工程文件这里npm install就直接会直接生成模块以及文件夹的文件
路径
- 在require("")包的时候,只要在一个磁盘,只要你的相对路径正确,无论你引进的在哪个磁盘,都会从自身的这个文件开始一层一层找到这个文件。
- 但是在fs.readfile()的时候,如果cmd的前面的路径不在自己的文件位置,在readFile里面用相对路径的话,就找不到这个文件,所以必须在readFile()这里,用绝对路径。
3.这个_dirname就默认将前面缺少的这个位置给补上,就相当于读取的是绝对路径,就不用再考虑命令行的路径问题。
fs.readFile("_dirname + "相对路径"",function(err, data){});
- 这个在一个a.js引用b.js,b.js readFile()一个txt文件,而这些位置都不在一起。那么,在node a.js的时候位置就找不到txt的文件,因为txt文件是相对于b.js文件来写的。
关于路由的应用
use.js
exports.showIndex = function (req, res) {
res.writeHead(200,{"Content-type":"text/html;charset = UTF-8"});
res.end("我说首页");
}
exports.showStudent = function (req, res) {
res.writeHead(200,{"Content-type":"text/html;charset = UTF-8"});
res.end("我是学生");
}
exports.show404 = function (req, res) {
res.writeHead(404,{"Content-type":"text/html;charset = UTF-8"});
res.end("错了");
}
show.js
var http = require('http');
var use = require('./use.js');
http.createServer(function (req, res) {
if(req.url == '/') {
use.showIndex(req, res);
}else if(req.url.substr(0,9) == '/student/') {
use.showStudent(req, res);
}else {
use.show404(req, res);
}
}).listen(8000);
console.log("你好");
在这里,我也进行了req,res的传参应用。
post请求
相对于get,post比较复杂,node认为post数据会比较多,那么,它就把这些数据分为众多的数据块,然后通过特定的事件,将这些数据传给回调函数。
post.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>提交</title>
</head>
<body>
<form action="http:127.0.0.1:8000/dopost" method="post">
<p>
姓名:<input type="text" name="name">
</p>
<p>
性别:<input type="radio" name="sex" value="男">男
<input type="radio" name="sex" value="女">女
</p>
<input type="submit">
</form>
</body>
</html>
post.js
var http = require('http');
//创建http服务器
http.createServer(function (req, res) {
//在前面的页面的url等于这个并且为Post的时候就读取这个请求的内容
if(req.url == "/dopost" && req.method.toLowerCase() == "post") {
var alldata = "";
//post是分块来请求的,所以要一直监听
//可能接受了一小段,就去服务别人了,防止遇到更大的表单
req.addListener("data", function (chunk) {
alldata += chunk;
});
//在监听结束的时候打印请求的内容
req.addListener("end", function () {
console.log(alldata.toString());
});
}
res.end();
}).listen(8000);
- s所请求的格式仍然为get的格式
- 如果想要单独获取各个的值,就必须利用querystring模块的parse来实现,将它转成对象。
var querystring = require('querystring');
//获取模块
req.addListener("end", function () {
var dataObj = alldata.toString()
// console.log(alldata.toString());
//利用查询模块将这个转为对象
var dataString = querystring.parse(dataObj);
console.log(dataString.name + '\n');
console.log(dataString.sex);
});
- 如果为一个复选框,他可以直接将其转为数组。
name=cc&sex=%E5%A5%B3&hobby=%E7%94%BB%E7%94%BB&hobby=%E8%B7%B3%E8%88%9E
//此时有2个hobby
- 所以,转为字符串后,再将其parse后会形成一个Hobby数组。
{ name: ‘cc’, sex: ‘女’, hobby: [ ‘画画’, ‘跳舞’ ] }
console.log(dataString.hobby[0]);
formidable ##(重要)
- 如果想要上传文件,则需要先下载formidablea模块,在html文件的form中需要加上enctype=“multipart/form-data”,表示要上传文件。
- 然后需要新建一个upload的文件夹,保存上传的文件。这时需要修改上传的地址form.uploadDir = “./upload”;,根据模块的相应的函数定义来找上传的文件,其中回调函数中的field放文本框或者单选框复选框,包括tupian的内容,但是files就直接保存了文件。
post.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>提交</title>
</head>
<body>
<form action="http://127.0.0.1:3000/dopost" enctype="multipart/form-data" method="post" >
<p>
姓名:<input type="text" name="name">
</p>
<p>
性别:<input type="radio" name="sex" value="男">男
<input type="radio" name="sex" value="女">女
</p>
<p>
爱好:<input type="checkbox" name="hobby" value="画画">画画
<input type="checkbox" name="hobby" value="跳舞">跳舞
<input type="checkbox" name="hobby" value="唱歌">唱歌
</p>
<p>
<input type="file" name="tupian"/>
</p>
<input type="submit" />
</form>
</body>
</html>
post.js
var http = require('http');
//引进查询模块
var querystring = require('querystring');
var formidable = require('formidable');
//创建http服务器
var server = http.createServer(function (req, res) {
//在前面的页面的url等于这个并且为Post的时候就读取这个请求的内容
if(req.url == "/dopost" && req.method.toLocaleLowerCase() == "post") {
var form = new formidable.IncomingForm();
//调整上传文件的路径
form.uploadDir = "./upload";
//执行回调函数的时候,就已经接受表单数据全部完毕
form.parse(req, function (err, fields, files) {
// if(err) {
// throw err;
// }
//所有的文件数据都放在files里面
//所有的文本域、单选框都在fileds存放
console.log(fields);
console.log(files);
res.writeHead(200, {"Content-type": "text/html;charset=UTF8"});
res.write("hah");
res.end('成功');
});
}
})
server.listen(3000);
field的内容
注意这里,复选框最后一个将其覆盖,并没有显示数组
file内容
此时的upload
**补充:**util.inspect({field: field, file: file});能够查看内容,但是必须先引入util的工具包。
上传改名
- 用fs.rename(oldpath,newpath),其中,这个Path是相对于命令行的路径,所以在用得时候最好加"+ _dirname +".
- 首先,要引进一些模块,进行改名
var path = require('path');
//想要获取扩展名
var fs = require('fs');
//想要用rename
var sd = require('silly-datetime');
//想要以日期的相应的格式进行重命名
var ttt = sd.format(new Date(), 'YYYYMMDDHHmmss');
//用相应的日期模块
var extname = path.extname(files.tupian.name);
//获取扩展名,这个name是 name: '01.png',
var oldname = __dirname + "/" + files.tupian.path;
//这个path是path: 'upload\\upload_0c4de01901a712e69fb3732b78b19066',
var newname = __dirname + "/upload/" + ttt + extname;
fs.rename(oldname, newname, function(err) {
if(err) {
throw Error("改名失败");
}
res.writeHead(200, {"Content-type": "text/html;charset=UTF8"});
res.end('成功');
})
- 把静态html页面也放在服务器上跑。
else if(req.url == "/") {
fs.readFile("./post.html", function(err, data) {
res.end(data);
})
}else {
res.end('404');
}
ejs模板引擎
- 先在命令行进行npm install ejs
- 利用ejs.render()进行数据绑定
var ejs = require('ejs');
//引进模板
//字符串
var string = "我买了一个Iphone<%= a%>s";
//数据
var data = {
a : 6
}
//数据绑定
var str = ejs.render(string, data);
console.log(str);
- 将模板单独放在一个文件里.ejs。
index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>提交</title>
</head>
<body>
<h1>好搞笑啊,我今天买了一个IPHONE<%= a%>s</h1>
</body>
</html>
ejs.js
var ejs = require('ejs');
var http = require('http');
var fs = require('fs');
//引进模板
http.createServer(function (req, res) {
fs.readFile("./index.ejs",function (err, data) {
var template = data.toString();
var dictionary = {a: 6};
var html = ejs.render(template, dictionary);
console.log(html);
res.writeHead(200, {"Content-type": "text/html;charset=UTF8"});
res.end(html);
});
}).listen(8000);
- 传数组也是
index.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>提交</title>
</head>
<body>
<h1>好搞笑啊,我今天买了一个IPHONE<%= a%>s</h1>
<ul>
<% for(var i = 0; i < num.length; i++) {
if(num[i].count>110) {
%>
<li>
<%=num[i].name %>
</li>
<% }
}%>
</ul>
</body>
</html>
ejs.js
var ejs = require('ejs');
var http = require('http');
var fs = require('fs');
//引进模板
http.createServer(function (req, res) {
fs.readFile("./index.ejs",function (err, data) {
var template = data.toString();
var dictionary = {
a: 6,
num:[
{"name":"hahah", "count":111},
{"name":"hfffffh", "count":12},
{"name":"heeeeh", "count":1111}
]
};
var html = ejs.render(template, dictionary);
console.log(html);
res.writeHead(200, {"Content-type": "text/html;charset=UTF8"});
res.end(html);
});
}).listen(8000);
- 会使得前后台模糊不清,杂乱无章
jade模块
–jade后台是通过字符串处理–
–用缩进代表标签–
已被淘汰
学习node第三阶段
express框架
- 原生node的问题
- 传递页面不方便,需要HTTP请求,要考虑304问题
- 路由不清晰,需要很多正则表达式的判断和字符串函数
- 要考虑很多其他问题–
- 首先,需要npm install --save-dev express,因为,save可以生成json文件,实时更新package.json文件,自动添加依赖。
express.js
var express = require('express');
var app = express();
//这里必须调用express()函数将返回值传给app
//这里的get可以将路由写的很好,取代了http的功能
app.get("/",function (req, res) {
//在这里用res的send函数将内容返回去相当于end
res.send("哈哈哈哈哈");
});
//这里用正则表达式进行路由的功能,就不用引号
app.get(/^\/student\/([\d]{10})$/, function (req, res) {
//这里使用圆括号的意义就在于找到第一个匹配这里的值,再将这个通过第一个params【0】给获取
res.send("学生学号是" + req.params[0]);
});
//这里通过冒号使得gonghao为一个变量,当传给它一个值得时候,就会赋值给Gonghao
app.get("/teacher/:gonghao", function (req, res) {
//这里用params.gonghao获取这个变量的值
res.send("老师工号是" + req.params.gonghao);
});
app.listen(8000);
- 静态文件的管理,不用再写/static/+dirname
app.use(express.static("./public"));
- 使用ejs模板引擎
express2.js
var express = require('express');
//这里就不用将ejs引进了
var app = express();
//在这里写入模板引擎用ejs
app.set("view engine", "ejs")
app.get("/", function (req, res) {
//用render赋给文件haha.ejs但这里不用写views
res.render("haha", {
num: [
"qqqq",
"ssss",
"wwww"
]
});
});
app.listen(8000);
./views/haha.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>提交</title>
</head>
<body>
<ul>
<% for(var i = 0; i < num.length; i++) { %>
<li>
<%=num[i] %>
</li>
<% } %>
</ul>
</body>
</html>
路由
- app.get(“地址”, function(){});get方法获取
- app.post(“地址”, function(){});post方法获取
- app.all(“地址”, function(){});用任意方法获取地址
在这里不区分大小写;并且忽略?以及#参数以及文件后面传递的参数 - 在这里可以用职正则表达式,用()起来的用req.param[]获取
- 也可以用冒号加上去,后面加一个变量,具体看上一章
注意:zl/里面/也可以加:y以表示变量
restful路由设计
get是获取信息
add是添加信息
delete是删除信息
post是查询信息
对于网页的请求不同就对这个的使用不同
中间件
在原生的node里面,只会执行http.createSever的函数里面的语句,外面的语句只是在第一次打开网页的时候执行一次。
middle.js
var http = require('http');
//这个就是打开的时候执行一次,再次刷新就不执行了
var a = 100;
http.createServer(function (req, res) {
a++;
res.end(a.toString());
}).listen(4000);
- 当路由相同的时候,会从上往下找匹配的项,当匹配上了,则不会再往下找。
但是next()会可继续找下面的路由get
var express = require('express');
var a = 100;
var app = express();
app.get('/',function (req, res, next) {
console.log(1);
next();
});
app.get('/', function (req, res) {
console.log(2);
});
app.listen(8000);
`````
- 像这个就会被第一个干掉
var express = require('express');
var a = 100;
var app = express();
app.get('/:username/:id',function (req, res) {
console.log(1);
});
//当加/admin/login的时候,就会被第一干掉
app.get('/admin/login', function (req, res) {
console.log(2)s});
app.listen(8000);
- 解决方法
- 将2 个方法调换,将admin放在上面
- 在上面的方法加next但是会继续匹配下面的,就会报错;在上面检索数据库,如果
数据库没有就next()
- 路由get、post都是中间件,他们按照顺序向下读取
中间件
app.use()也是获取地址,但它的地址是一个子文件夹,也就是说,当写地址为/admin的时候,在输入网址的时候,/admin/sddfffff都是可以匹配的,但是其他的中间件就不行
var express = require('express');
var a = 100;
var app = express();
app.use('/admin',function (req, res) {
res.write(req.originalUrl + "\n");
res.write(req.baseUrl + "\n");
res.write(req.path + "\n");
res.end("hello");
});
app.listen(8000);
var express = require('express');
var a = 100;
var app = express();
app.use('/',function (req, res) {
console.log(2);
})
app.use('/admin',function (req, res) {
res.write(req.originalUrl + "\n");
res.write(req.baseUrl + "\n");
res.write(req.path + "\n");
res.end("hello");
});
app.listen(8000);
这样的话,就不会执行下面的语句了。当不写地址的时候,就相当于把地址作为/以及任何地址,所以必须要有Next()
- 可以将功能传给第三方模块
- use提供的有功能的场所,其实他的功能都能通过第三方模块可以获得
//静态服务
app.use(express.static("./public"));
静态服务一般写在上面
//静态服务
app.use("/jingtai", express.static("./public"));
可以通过这个jingtai 进去public 到文件夹
- express自带404
//一般将它放在下面,进行错误判断,进入err的页面
app.use(function (err, req, res) {
if(err) {
res.send("404");
}
})
render 和 send
- 可以用render进行渲染呈现模板引擎,将会根据views文件夹里面的内容进行渲染,如果想改文件夹的名字,可以用app.set(“views”,“sssss”),并把haha.ejs放在sssss里面
//ejs不能改名字
app.set(“view engine”, “ejs”)
- send是根据它自己加200状态码Mime类型,但是只能用一次
get和post
- 在express中,可以不用url模块获取get请求的参数,有一个query的对象
- post请求必须用body-parser模块,,使用后可以得到req.body参数,如果有表单上传问价,还是得用formidable模块
var express = require('express');
var app = express();
//引入bodyparser模块
var bodyparser = require('body-parser');
app.set("view engine", "ejs");
//加入模块的API
app.get("/", function (req, res) {
res.render("form2");
});
app.use(bodyparser.urlencoded({extended:false}));
app.post("/", function (req, res) {
//通过req.body获取请求的内容
if(!req.body) {
return res.sendStatus(404);
}
console.log(req.body);
});
app.listen(8000);
- 文件上传还是要用fomidable
学习node第四阶段
后台ejs
- 通过eJs模板来完成动态网页
- 通过将获取req的id变量来判断从数据库里面获取第几个数据
news.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>提交</title>
</head>
<style type="text/css">
.header {
margin: 0 auto;
width: 600px;
height: 300px;
background-color: #ccc;
}
.content {
margin: 0 auto;
margin-top: 40px;
background-color: #ccc;
}
</style>
<body>
<div class="header"></div>
<div class="content">
<div class="main">
<h1>高薪就业</h1>
<p><%= biaoti%><%= zuozhe%><%= shijian%></p>
<p><%= neirong%></p>
</div>
</div>
</body>
</html>
news.js
var express = require('express');
var app = express();
app.set("view engine", "ejs");
//模拟一个数据库
var shujuku = [
{
"biaoti": "我是0号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是1号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是2号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是3号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是4号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
}
];
app.get("/news/:id",function (req, res) {
//通过Id号来获取第几个数据库数据
var id = parseInt(req.params.id);
res.render("news", shujuku[id]);
});
app.listen(8000);
ajax后台提交
1.在这里注意将要写的内容放在模板的脚本里面
2.导入undercore利用里面的模板的函数,将请求的数据放在模板里面
3.导入jq用ajax的方法请求数据
4.用express的js文本在线将json数据写进来
5.把除了js文件的文件都放在静态文件夹里面
6.最后在html的请求的js文件里面将添加数据过后的内容加到html的内容块中
news.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>news</title>
</head>
<style type="text/css">
.header {
margin: 0 auto;
width: 600px;
height: 50px;
background-color: #ccc;
}
.content {
margin: 0 auto;
margin-top: 40px;
background-color: #ccc;
}
</style>
<body>
<div class="header"></div>
<div class="content">
<div class="main">
</div>
</div>
<script type="text/template" id="moban">
<div class="grid">
<h1>高薪就业</h1>
<p><%= biaoti%><%= zuozhe%><%= shijian%></p>
<p><%= neirong%></p>
</div>
</script>
<script src="jquery.js"></script>
<script src="undercore.js"></script>
<script type="text/javascript" >
//得到模板内容
var mobanString = $("#moban").html();
//用库里面的模板函数
var compiled = _.template(mobanString);
//用jq里面的ajax get方法获取数据
$.get("/news",function (data, status) {
//用循环将数据库里面的数据给导入进去
for(var i = 0;i<data.length;i++) {
//将利用类似render的方法获取数据并将这个的结果得到
var compiledString = compiled(data[i]);
//将这个内容加到content里面去
//加$会让它变成一个对象
$(".main").append($(compiledString));
}
})
</script>
</body>
</html>
app.js
var express = require('express');
var app = express();
app.use(express.static("./public"));
var shujuku = [
{
"biaoti": "我是0号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是1号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是2号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是3号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是4号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
}
];
app.get("/news", function (req, res) {
res.json(shujuku);
});
app.listen(8000);
- 在这里面,ajax彻彻底底将前端后台分开。
老牌数据库
- 老牌数据库(MySQL、SQL、Orcal、Access)的问题
- 如果想要增加一个字段的列,代价极大,因为之前的数据已经存在,我们的需求是以后填写的人才要写这个字段,但是它会在存在的数据上从头到尾过一遍,因为是一个结构化的数据库,所谓字段,应该每个数据都有信息,所以会影响所有的数据,但是,这样对于大数据,会耗时极其久 ,字段这个太不灵活
- 数据不灵活。一个字段需要同样类型的数据,不能一行记录是文本,一行记录是数字。
NoSQL应运而生
NoSQL
非结构型数据库,无行与列的概念
-
collections是可以存放不同类型的Json文档
-
文件是存放一个json的内容
-
都是js范畴的事情
-
有些系统需要筛选,比如筛选出大于20 的女生的信息,这时用SQL就可以、
-
但是有些只需要存储数据,不需要筛选为了提高效率和性能,就用NoSQL
-
数据模型比较简单
-
需要灵活性更强的IT系统
-
对数据库性能要求高
-
不需要高度的数据一致
-
对于给定的key,比较容易映射复杂值的环境
关于mongodb的安装与使用,见我博客!
node.js与mongo的连接使用
- 先npm install mongodb下载安装
一下一个例子为说明,这里以插入数据为例,更新删除以及查找类似,都如同Mongodb的语句。
app.js
var express = require('express');
var app = express();
var MongoClient = require('mongodb').MongoClient;
app.use(express.static("./public"));
var shujuku = [
{
"biaoti": "我是0号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是1号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是2号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是3号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
},
{
"biaoti": "我是4号新闻",
"zuozhe": "黄瑞琪",
"shijian": "2017",
"neirong": "<p>内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊内容啊</p>"
}
];
var insertData = function(db, callback) {
//连接到表 haha
var collection = db.collection('haha');
//插入数据
var data = [{"name":"菜鸟教程","age":3},{"name":"菜鸟工具","age":5}];
collection.insert(data, function(err, result) {
if(err)
{
console.log('Error:'+ err);
return;
}
callback(result);
});
}
app.get("/news", function (req, res) {
//建立连接数据库地址,如果数据库不存在,系统会新建一个数据库
var url = "mongodb://localhost:27017/haha";
//连接数据库
//db代表当前数据库内容
MongoClient.connect(url, function(err, db) {
if (err) {
console.log("数据库连接失败");
return;
};
console.log("数据库已创建!");
insertData(db, function (result) {
console.log(result);
db.close();
})
});
res.json(shujuku);
});
app.listen(8000);
- 接下来用DAO层的封装来实现连接数据库
db.js
var MongoClient = require('mongodb').MongoClient;
//建立连接数据库地址,如果数据库不存在,系统会新建一个数据库
//连接数据库
function __connectDB(callback) {
var url = "mongodb://localhost:27017/haha";
MongoClient.connect(url, function(err, db) {
if (err) {
console.log("数据库连接失败");
return;
};
console.log("数据库已创建!");
callback(err, db);
});
}
// __connectDB();
//插入数据
//表示成功之后要做的事情
exports.insertOne = function (collectionName, json, callback) {
__connectDB(function (err, db) {
db.collection(collectionName).insertOne(json, function (err, result) {
callback(err, result);
db.close();
})
});
}
app2.js
var express = require('express');
var app = express();
var db = require('./model/db.js');
app.get("/", function (req, res) {
db.insertOne('haha', {"name": "ss", "age": 4}, function (err, result) {
if(err) {
console.log("失败");
return;
}
res.send(result);
})
});
app.listen(8000);