Node.js的特点
- 事件驱动
- 非阻塞IO模型(异步)
- 轻量和高效
Node的使用
模块的导入导出
- require
## require函数用来在一个模块中引入另外一个模块
let cc1 = require('./main.js')
let cc2 = require('home/src/main.js')
let cc3 = require('./main')
## 作用
* 执行导入的模块中的代码
* 返回导入模块中的借口对象
- exports
## exports对象用来导出当前模块的公共方法或属性,别的模块通过require函数使用当前模块时得到的就是当前模块的exports对象。
exports.add = function() {
let i = 0
console.log(++i)
}
## 导出一个add方法供其他模块使用
## 其实exports类似于ES6中的export的用法,用来导出一个指定名字的对象
- module.expots
## module.exports 用来导出一个默认对象,没有指定对象名,常见于修改模块的原始导出对象。
module.exports = function() {
console.log('hello world!');
}
- 模块的初始化
## 一个模块中的js代码仅在模块第一次被使用时执行一次,并且在使用的过程中进行初始化,之后缓存起来便于后续继续使用。
- 主模块
## 通过命令行参数传递给NodeJs以启动程序的模块被称为主模块。主模块负责调度组成整个程序的其它模块完成工作。例如通过以下命令启动程序时,main.js就是主模块。
$ node main.js //运行main.js启动程序,main.js称为主模块
npm 常见命令
- npm -v:查看npm版本
- npm init:初始化后会出现一个package.json配置文件。可以再后面加上-y,快速跳过问答式界面
- npm install:会根据项目中的package.json文件自动下载项目所需的全部依赖
- npm install 包名 --save-dev(npm install 包名 -D):安装的包只用于开发环境,不用于生产环境,会出现在package.json文件中的devDependencies属性中
- npm install 包名 --save(npm install 包名 -S):安装的包需要发布到生产环境的,会出现在package.json文件中的dependencies属性中
- npm list:查看当前目录下已安装的node包
- npm list -g:查看全局已经安装过的node包
- npm --help:查看npm帮助命令
- npm update 包名:更新指定包
- npm uninstall 包名:卸载指定包
- npm config list:查看配置信息
- npm 指定命令 --help:查看指定命令的帮助
- npm info 指定包名:查看远程npm上指定包的所有版本信息
- npm config set registry registry.npm.taobao.org:修改包下载源,此例修改为了淘宝镜像。
- npm root:查看当前包的安装路径
- npm root -g:查看全局包的安装路径
- npm ls 包名:查看本地安装指定包及版本信息,没有显示empty
- npm ls 包名 -g:查看全局安装的指定包及版本信息,没有显示empty
fs文件系统模块
文件的读写
- 文件读取
## 同步读取操作
var buf = Buffer.alloc(20);
var content = fs.readFileSync('hello.txt', {flag: 'r', encoding: 'utf-8'})
console.log(content)
## 异步读取操作
fs.readFile('hello.txt', {flag: 'r', encoding: 'utf-8'}, (err, data) => {
if(err) {
console.log(err)
}else {
console.log(data)
}
})
## 异步读取操作方法优化-封装promise
function fsRead(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, { flag: 'r', encoding: 'utf-8' }, (err, data) => {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
var w1 = fsRead('hello.txt')
w1.then(function(res) {
console.log(res)
})
async function ReadList() {
var file2 = await fsRead('hello.txt');
var file3 = await fsRead(file2 + ".txt");
var file3Content = await fsRead(file3 + ".txt");
console.log(file3Content)
}
ReadList()
- 文件写入
## 写入文件操作(覆盖)
fs.writeFile('test.txt', '晚饭吃啥?', {flag: 'w', encoding: 'utf-8'}, function (err) {
if(err) {
console.log('写入内容出错')
}else {
console.log('写入内容成功')
}
})
## 文件追加内容
let fs = require('fs');
fs.writeFile('test.txt', '红烧狮子头\n', {flag: 'a', encoding: 'utf-8'}, function (err) {
if(err) {
console.log('写入内容出错')
}else {
console.log('写入内容成功')
}
})
## 异步写入操作方法优化-封装promise
function writefs(path, content) {
return new Promise((resolve, reject) => {
fs.writeFile(path, content, { flag: 'a', encoding: 'utf-8' }, function (err) {
if (err) {
reject(err)
} else {
resolve(err)
}
})
})
}
async function writeList() {
await writefs('test.txt', '1今天吃烧烤\n');
await writefs('test.txt', '2今天吃烧烤\n');
await writefs('test.txt', '3今天吃烧烤\n');
await writefs('test.txt', '4今天吃烧烤\n');
}
writeList();
- 删除文件
let fs = require('fs');
fs.unlink('test.txt', function() {
console.log('成功删除!')
})
Buffer的使用
//1、数组不能进行二进制数据的操作
//2、js数组不像java、python等语言效率高
//3、buffer内存空间开辟出固定大小得内存
- 将字符串转成buffer对象
var str = 'helloworld'
let buf = Buffer.from(str)
console.log(buf)
- 输出buffer内容
console.log(buf.toString())
- 开辟一个空的buffer(缓存区)
let buf1 = Buffer.alloc(10)
buf1[0] = 10
console.log(buf1)
//不安全-未清空内存区
let buf2 = Buffer.allocUnsafe(10)
console.log(buf2)
目录的读取
- 读取指定路径的文件目录
fs.readdir('../03fs', function(err, files) {
if(err) {
console.log(err)
}else {
console.log(files)
}
})
- 删除目录
fs.rmdir('abc', function() {
console.log('删除成功')
})
Stream文件流的使用
- 写入流
let fs = require('fs');
//1创建写入流
// --语法:fs.createWriteStream(文件路径,【可选的配置操作】)
let ws = fs.createWriteStream("hello.txt", { flags: 'w', encoding: 'utf-8' });
console.log(ws);
//监听文件打开事件
ws.on('open', function () {
console.log('文件打开')
})
//监听准备事件
ws.on('ready', function () {
console.log('文件写入已准备状态')
})
//监听文件关闭事件
ws.on('close', function () {
console.log('文件写入完成,关闭')
})
//文件流式写入
ws.write("helloworld!", function (err) {
if (err) {
console.log(err);
}else {
console.log('内容流入完成')
}
});
//文件写入完成
ws.end(function() {
console.log('文件写入关闭')
});
- 读取流
let fs = require('fs');
const { randomBytes } = require('crypto');
//创建读取流,语法:fs.createReadStream(路径,【可以选的配置项】)
let rs = fs.createReadStream('hello.txt', {flags: 'r', encoding: 'utf-8'})
console.log(rs);
rs.on('oprn', function() {
console.log('读取的文件打开')
})
rs.on('close', function() {
console.log('读取流结束')
})
// 每一批数据的流入完成
rs.on('data', function(chunk) {
console.log('单批数据流入:' + chunk.length)
console.log(chunk)
})
- 管道流
let fs = require('fs');
const { randomBytes } = require('crypto');
//创建读取流,语法:fs.createReadStream(路径,【可以选的配置项】)
let rs = fs.createReadStream('hello.txt', {flags: 'r', encoding: 'utf-8'})
let ws = fs.createWriteStream('a.txt', {flags: 'w', encoding: 'utf-8'})
console.log(rs);
rs.on('open', function() {
console.log('读取的文件打开')
})
rs.on('close', function() {
console.log('读取流结束')
})
rs.pipe(ws);
readline模块的使用
输入输出
let readline = require('readline');
//导入readline包
//实例化接口对象
var rl = readline.createInterface({
output: process.stdout,
input: process.stdin
})
//设置rl,提问时间
rl.question('今晚吃啥?', function (answer) {
console.log("答复:", answer);
rl.close();
})
rl.on('close', function () {
process.exit(0);
})
node事件-events模块
- 使用on定义事件并触发
let events = require('events')
let fs = require('fs')
let e = new events.EventEmitter()
e.on('helloSuccess', function(eventMsg) {
console.log('1吃夜宵')
})
e.on('helloSuccess', function(eventMsg) {
console.log('2唱k')
})
e.on('helloSuccess', function(eventMsg) {
console.log('3打王者')
})
e.on('helloSuccess', function(eventMsg) {
console.log('4打dota')
})
fs.readFile('hello.txt', {flag: 'r', encoding: 'utf-8'}, function(err, data) {
if(err) {
console.log(err)
}else {
e.emit('helloSuccess', data);
}
})
路径模块和系统模块
- 路径模块的使用-path模块
let path = require('path')
let fs = require('fs')
// console.log(path)
// let strPath = "http://www.xinhuanet.com//2019-11/23/c_1125266028.htm"
let strPath = "http://www.newsimg.cn/xjp20171103/images/xjp_banner.jpg"
//获取路径信息的扩展名
let info = path.extname(strPath);
// console.log(info);
let arr = ['/sxt', 'qianduan', 'zhongji']
let info1 = path.resolve(...arr)
// console.log(info1)
//获取当前执行目录的完整路径
// console.log(__dirname)
let info2 = path.join(__dirname,'sxt', 'qianduan', 'zhongji');
// console.log(info2)
//
let str = 'http://www.sxt.com/07PATH/xinwen/guonei.html'
//解析出请求目录
let arrParse = str.split('/')
// console.log(arrParse)
let arrTemp = arrParse.slice(-2)
// console.log(arrTemp)
let filePath = path.join(__dirname,...arrTemp)
console.log(filePath)
fs.readFile(filePath, {encoding: 'utf-8'}, function(err, data) {
if(err) {
console.log(err)
} else {
console.log(data)
}
})
- 系统模块的使用-os模块
let os = require('os')
// console.log(os)
//查看cpu信息
console.log(os.cpus())
//查看整个内存大小
console.log(os.totalmem())
//查看内存架构
console.log(os.arch())
//查看剩余内存量
console.log(os.freemem());
数据爬取-url模块
const { readFile } = require("fs");
let url = require('url')
// console.log(url)
let httpUrl = "https://sale.vmall.com/hwmate.html?cid=10602"
let urlObj = url.parse(httpUrl)
// console.log(urlObj)
let targetUrl = "http://www.taobao.com/"
httpUrl = "./sxt/qianduan/laochen.html"
let newUrl = url.resolve(targetUrl, httpUrl)
console.log(newUrl)
axios模块
let axios = require('axios')
// console.log(axios)
// let httpUrl = "https://www.dytt8.net/index.htm"
// let httpUrl = "https://api.apiopen.top/getJoke?page=1&count=10&type=image"
let httpUrl = "https://www.1905.com/vod/list/n_1_t_1/o3p1.html"
//获取其实页面的所有分类地址
async function getClassUrl(httpUrl) {
let res = await axios.get(httpUrl)
let reg = /<span class="search-index-L">栏目(.*?)<div class="grid-12x">/igs
//解析html内容
let result = reg.exec(res.data)[1]
// console.log(res)
let reg1 = /<a href="(.*?)".*?>(.*?)<\/a>/igs
let arrClass = []
var temp;
while (temp = reg1.exec(result)) {
let obj = {
className: temp[2],
url: temp[1]
}
arrClass.push(obj)
getMovies(temp[1])
}
// console.log(arrClass)
}
//通过分类,获取页面中的电影链接
async function getMovies(url) {
let res = await axios.get(url);
// console.log(res.data)
let reg = /<a class="pic-pack-outer" target="_blank" href="(.*?)".*?>/
var temp;
let arrList = [];
while (temp = reg.exec(res.data)) {
console.log(temp);
//改进,可以改为迭代器,提升性能
arrList.push(temp[1])
}
console.log(arrList);
}
// axios.get(httpUrl).then(function (res) {
// console.log(res)
// })
getClassUrl(httpUrl)
服务器部署到公网(花生壳)
node操作数据库
1.下载mysql插件
npm install mysql
2.创建数据库链接对象
let options = {
host: 'localhost',
// port: '3306',//可选,默认是3306
user: 'root',
password: 'root',
database: 'mall'
}
//创建与数据库的连接的对象
let con = mysql.createConnection(options);
3.建立连接
con.connect((err) => {
//如果建立连接失败
if (err) {
console.log(err)
} else {
console.log("连接成功")
}
});
4.执行sql语句
let strSql = "select * from user";
con.query(strSql, (err, results, fields) => {
console.log(err);
console.log(results)
console.log(fields)
})
express框架的使用
express项目的创建
- 下载express插件
npm install express --save
- 创建一个名为myapp的Express应用,并使用ejs模板引擎
express --view=ejs app
- express生成器快速生成项目
express moviesapp -e
express路由的使用
1.字符串的路由模式
app.get('/', (req, res) => {
res.send('这是首页')
})
2类字符串的正则模式
//例如:匹配2个路径abcd或者acd
app.get('/ab?cd', (req, res) => {
res.send('这是abcd/acd')
})
//例如路径:/ab+cd /abcd /abbcd /abbbbcd
//例如路径:/ab*cd,必须以ab开头,cd结尾,中间可以有任意的东西
3正则的匹配模式
app.get(/\/a\d{10,}/, (req, res) => {
res.send('新闻页面')
})
4动态路由
app.get('/news/:cataoryid/a:newsid',
(req, res, next) => {
req.params.customHost = '127.0.0.1'
next()
},
(req, res, next) => {
res.send('新闻id页面:\n' + JSON.stringify(req.params))
})
使用ejs模板
-
添加ejs模板配置
-
ejs文件语法
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8>
<title></title>
</head>
<body>
<% for(var i=0;i<10;i++){ %>
<%= i %>
<% } %>
<!-- 获取变量 -->
<div class="datas">
<p>获取变量:</p>
<%- title %>
<%= title %>
</div>
</body>
</html>
# <% xxx %>:里面写入的是js语法
# <%= xxx %>:里面是服务端发送给ejs模板转义后的变量,输出为原html
# <%- xxx %>:里面也是服务器端发送给ejs模板后的变量,不过他会把html输出来
# <%_ xxx _%>:删除内容前和后的空格符
# <%#:注释标签,不执行、不输出内容
# -%>:删除紧随其后的换行符
中间件(拦截器)
- 执行过程
- 浏览器发送请求
- express接受请求
- 中间处理的过程(中间件)
- 路由函数处理渲染(req,res)
- res.render渲染
- 示例(可以截获请求,不执行next则中断后续操作)
//添加中间件
app.use(function(req, res, next) {
console.log('访问任何页面,此函数都会被调用!')
next()
})
- 路由中间件
let router1 = express.Router();
router1.get('/', (req, res) => {
res.send('商城首页')
})
router1.get('/list', (req, res) => {
res.send('商城产品列表页')
})
//实例化路由模块,此路由模块相当于一个小的app实例
app.use('/mall', router1)
cookie的使用
sesssion的使用
multer中间件的使用(上传文件的实现)
医院管理系统
前台
- 首页
- 医院介绍
- 新闻中心
- 预约挂号
后台
- 用户管理,添加删除修改用户资料
- 权限管理,用户有哪些的权限,有些页面只有某部分特殊用户可以访问。
- 登陆注册
- 新闻信息管理
- 新闻分类管理
- 医生管理
- 患者管理
- 挂号管理
- 药品管理
- 财务统计
权限管理
权限管理需要的数据表
- 用户表
- 角色表
- 权限表
举例: 张三用户是一个管理员,那么管理员就有(编辑用户,编辑新闻,编辑挂号,查看统计数据)
设置权限表
- 添加/删除/需改权限
- 字段:
- 权限编码,id
- 编辑用户权限,权限名称
- /damin/users/userlist,访问路径