Node.js学习

Node.js学习笔记

Node.js简介

  • 简单的说 Node.js 就是运行在服务端的 JavaScript。
    Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。
    Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。

Node.js第一个应用

  • 创建一个http服务器
const http = require('http')
const url=require('url')
const app = http.createServer()
app.on('request', (req, res) => {
    let {query,pathname}=url.parse(req.url,true)
    console.log("路径名为"+pathname)
    res.writeHead(200,{
        'content-type':'text/html;charset=utf-8'
    })
    res.end("<h1>请求信息成功</h1>")
}).listen(3000)
console.log('服务器正在监听3000端口')
  • 引入http模块,创建完成后,运行,即可在3000端口访问到服务器
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Node.js异步

避免回调地狱的两种方法

  • promise对象,使用promise对象的reject方法导出错误信息,resolve方法导出正确信息
const fs=require('fs')
new Promise((resolve, reject)=>{
    fs.readFile('./1.txt','utf8',(err,data)=>{
        if (err){
            reject(err)
        }else {
            resolve(data)
        }
    })
}).then(result=>console.log(result));`
  • async关键字,在函数名前加上async关键字使函数变为异步函数,使用await关键字使异步函数阻塞运行
const fs=require('fs')
const promisify=require('util').promisify //改造现有api
const read = promisify(fs.readFile)
async function run() {
    let r1=await read('./1.txt','utf8')
    let r2=await read('./2.txt','utf8')
    let r3=await read('./3.txt','utf8')
    console.log(r1)
    console.log(r2)
    console.log(r3)
}
run()

Node.js模块化开发

  • 使用require引入模块:
const http = require('http')
require方法中可以传入,相对路径,绝对路径
  • 使用module.exports将自己创建的模块开放出去供其他模块使用:
module.exports={开放的内容}  //开放的内容可以是一个函数,一个对象都可
exports.开放的内容=开放的内容
两种方式都可导出模块
不建议同时使用 exports 和 module.exports
如果先使用 exports 对外暴露属性或方法,再使用 module.exports 暴露对象,会使得 exports 上暴露的属性或者方法失效。
原因在于,exports 仅仅是 module.exports 的一个引用。

Node.js模块系统

  • 文件系统模块:
读取文件:
let fs = require("fs");
// 异步读取
fs.readFile('input.txt', (err, data)=> {
   if (err) {
       return console.error(err);
   }
   console.log("异步读取: " + data.toString());
});

// 同步读取
let data = fs.readFileSync('input.txt');
console.log("同步读取: " + data.toString());
写入文件:
fs.writeFile("./input.txt","hello",err=>{
    if (err!=null){
        return console.log(err.toString())
    }
    console.log("文件写入成功!")
})
  • path模块:因为各个操作系统的路径分隔符不同,模块可以使用当前操作系统的路径分隔符拼接路径
const path=require('path')
path.join(__dirname, 'public') 
__dirname为全局对象,用于获取当前文件的绝对路径
  • config模块:可以读取配置文件的内容,当拼接数据库连接url时可以使用这个模块获取配置信息
//导入config模块
const config=require('config')
const url=`mongodb://${config.get("db.user")}:${config.get("db.pwd")}@${config.get("db.host")}:${config.get("db.port")}/${config.get("db.name")}`
配置文件内容为:
{
 "db": {
   "user": "blog",   //用户名
   "host": "localhost",  //密码
   "port": "27017",   //端口号
   "name": "blog"    //数据库名称
 }
}
{
  "db": {
    "pwd": "APP_PASSWORD"  //APP_PASSWORD是系统环境变量的一个值,将密码保存在环境变量中,增加安全性
  }
}
  • serve-static模块,开放静态资源的模块:
const serveStatic=require('serve-static')  //引入模块
const serve=serveStatic(path.join(__dirname,'public'))   //告诉静态资源的位置
serve(req,res,()=>{})   //开放静态资源
  • dateformat模块:时间格式化模块,可以在模板中格式化时间:
const dateFormat=require('dateformat')
dateFormat(需要格式化的时间,'yyyy年mm月dd日')
  • gulp模块,对完成的文件进行压缩等操作:
const gulp = require('gulp')
const htmlmin = require('gulp-htmlmin')
const fileinclude = require('gulp-file-include')
const less = require('gulp-less')
const csso = require('gulp-csso')
const babel = require('gulp-babel')
const uglify = require('gulp-uglify')
//对html文件压缩
gulp.task('htmlmin', () => {
    return gulp.src('./src/*.html')
        .pipe(fileinclude())
        .pipe(htmlmin({collapseWhitespace: true}))
        .pipe(gulp.dest('./dist/'))
})
//对css文件压缩
gulp.task("cssmin", () => {
    return gulp.src(['./src/css/*.less', './src/css/*.css'])
        .pipe(less())
        .pipe(csso())
        .pipe(gulp.dest('./dist/css'))
})
//对js文件压缩
gulp.task('jsmin', () => {
    return gulp.src('./src/js/*.js')
        .pipe(babel({
            presets: ['@babel/env']
        }))
        .pipe(uglify())
        .pipe(gulp.dest('./dist/js'))
})
//文件的复制
gulp.task('copy', async () => {
    await gulp.src('./src/images/*')
        .pipe(gulp.dest('./dist/images'))
    gulp.src('./src/fonts/*')
        .pipe(gulp.dest('./dist/fonts'))
})

gulp.task('default', gulp.series(gulp.parallel('htmlmin', 'cssmin', 'jsmin', 'copy')));

queryString模块,可以将提交的表单数据转化为对象

const queryString=require('querystring')
let student=queryString.parse(formData) //formData为表单数据,student为转换的对象

Node.js路由

  • 使用路由模块,可以直接调用get,post方法来响应请求,而不再需要我们自己判断
const getRouter=require('router')  //引入路由模块
const router=getRouter()   //创建路由
//响应get请求
router.get('/add',(req,res)=>{
    const index=template('index',{})   //渲染模板
    res.end(index)   //响应信息
})
//响应post请求
router.post('/add',(req,res)=>{
    let formData=''
    req.on('data',param=>{
        formData+=param
    })
    req.on('end',async()=>{
        let student=queryString.parse(formData)
        await Student.create(student)
        res.writeHead(301,{
            Location:'/list'
        })
        res.end()
    })
})

Node.js全局对象

  • __dirname:当前文件所在目录
  • setTimeout():定时器
  • clearTimeout()清除定时器
  • setInterval()开启一个循环的定时器
function printHello(){
   console.log( "Hello, World!");
}
// 两秒后执行以上函数
setTimeout(printHello, 2000);
// 清除定时器
clearTimeout(t);
function printHello(){
   console.log( "Hello, World!");
}
// 两秒后执行以上函数
setInterval(printHello, 2000);
  • process进程对象:
//通过进程对象获取当前的系统环境输出不同的值
if (process.env.NODE_ENV==='development'){
    //开发环境
    app.use(morgan('dev'))
}else {
    //生产环境
    console.log('生产环境')
}

Node.js模板引擎

  • art-template模板引擎:
//引入模板
const template = require('art-template')
//引入时间格式化模块   
const dateFormat = require('dateformat')
//引入路径拼接模块
const path = require('path')
//将时间格式化模块导入到模板中,使所有模板都可以使用
template.defaults.imports.dateFormat = dateFormat
//设置要渲染的模板的目录
template.defaults.root = path.join(__dirname, '../', 'views')
//设置要渲染的模板的后缀名
template.defaults.extname = '.art'
//创建一个方法封装模板的渲染,
path为渲染的模板的路径,res为响应对象,object为要渲染的数据
module.exports=(path,res,object)=>{
    res.writeHead(200, {'content-type': 'text/html;charset=utf8'})
    res.end(template(path, object))
}
  • 模板语法
    – each循环:
{{each students}}
		<tr>
			<td>{{$value.name}}</td>
			<td>{{$value.age}}</td>
			<td>{{$value.sex=='0'?'男':'女'}}</td>
			<td>{{$value.email}}</td>
			<td>
				{{each $value.hobbies}}
				<span>{{$value}}</span>
				{{/each}}
			</td>
			<td>{{$value.collage}}</td>
			<td>{{dateFormat($value.enterTime,'yyyy年mm月dd日')}}</td>
		</tr>
{{/each}}

– if…else写法:

{{if admin}}
    {{include 'admin_content'}}
    {{each list}}
        <div>{{$index}}. {{$value.user}}</div>
    {{/each}}
{{/if}}

– include语句:可以导入模板中相同的部分,例如html的头部和尾部

{{include './common/header.art'}}

– block语句:可以创建一个块供其他模板在继承之后填入内容
extend语句:用于继承模板
父模板的html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title>Blog - Content Manager</title>
    <link rel="stylesheet" href="/admin/lib/bootstrap/css/bootstrap.min.css">
    <link rel="stylesheet" href="/admin/css/base.css">
    {{block 'link'}}{{/block}}
</head>
<body>
<!-- 创建一个块main,供其他模板填入内容 -->
{{block 'main'}}{{/block}}
<!-- /删除确认弹出框 -->
<script src="/admin/lib/jquery/dist/jquery.min.js"></script>
<script src="/admin/js/common.js"></script>
<script src="/admin/lib/bootstrap/js/bootstrap.min.js"></script>
<!-- 创建script块,供其他模板填入script内容 -->
{{block 'script'}}{{/block}}
</body>
</html>

子模版的html:

{{extend './common/layout.art'}}  //继承父模板
{{block 'main'}}   //填充main中的内容
{{include './common/header.art'}}   //引入头部模块
<!-- 主体内容 -->
<div class="content">
    <!-- 侧边栏 -->
    {{include './common/aside.art'}}   //引入侧边栏模块
    主体内容部分....
{{/block}}
//填充script块的内容
{{block 'script'}}
<script>
    $("#delete").on('click', function () {
        var id = $(this).attr('#data-id')
        // alert(id)
        $('#deleteId').val(id)
    })
</script>
{{/block}}

Node.js连接MongoDB数据库

  • 连接数据库:
//导入config模块
const config=require('config')
//导入mongoose模块
const mongoose=require('mongoose')
const url=`mongodb://${config.get("db.user")}:${config.get("db.pwd")}@${config.get("db.host")}:${config.get("db.port")}/${config.get("db.name")}`
mongoose.connect(url,{ useNewUrlParser: true , useUnifiedTopology: true,useCreateIndex:true })
    .then(()=>console.log('数据库连接成功'))
    .catch(()=>console.log("数据库连接失败"))
  • 创建集合规则:
const mongoose = require('mongoose')   //引入mongoose模块
const Joi = require('joi')   //引入joi模块,用于表单的验证
//创建集合规则
const userSchema = new mongoose.Schema({
    username: {
        type: String,
        required: true,
        minlength: 2,
        maxlength: 20
    },
    email: {
        type: String,
        required: true,
        unique: true
    },
    password: {
        type: String,
        required: true
    },
    role: {
        type: String,
        required: true
    },
    state: {
        type: Number,
        default: 0
    }
})
//使用model方法创建用户集合
const User = mongoose.model('User', userSchema)
//创建判断用户信息有效性的方法
const validateUser = user => {
    const schema = {
        username: Joi.string().min(2).max(10).required().error(new Error('用户名不符合规则')),
        email: Joi.string().email().required().error(new Error('邮箱格式不符合要求')),
        password: Joi.string().required().regex(/^[a-zA-Z0-9]{3,30}$/).error(new Error('密码不符合规则')),
        role: Joi.string().valid('normal', 'admin').required().error(new Error('角色不合法')),
        state: Joi.number().valid(0, 1).required().error(new Error('状态值不合法'))
    }
    return Joi.validate(user, schema)
}
//导出创建的用户集合和方法供其他模块使用
module.exports = {User,validateUser}
  • mongoose添加数据:
User.create(添加的数据对象).then(result => console.log(result))
    .catch(err=>{
     console.log(err.message)
    })
  • mongoose删除数据:
User.deleteMany(查询条件).then(data=>console.log(data))
User.findOneAndDelete({
    _id:'5c09f267aeb04b22f8460968'
}).then(result=>console.log(result))
  • mongoose查询数据:
//分页查询
User.find().skip(2).limit(3).then(data=>console.log(data))
//查询后排序
User.find().sort('-age').then(data=>console.log(data))
User.find(查询条件).then(data=>{
    console.log(data)
})
  • mongoose修改数据:
//修改多条数据
User.updateMany({},{age:25}).then(result=>console.log(result))
//修改一条数据
User.updateOne({
    name:'上官婉儿'
},{name:'张良'}).then(result=>console.log(result))

Node.js与express框架

  • express框架的应用:
//导入express框架
const express = require('express')
//创建服务器
const app = express()
//导入封装post请求体的模块
const bodyParser = require('body-parser')
//使用session
const session = require('express-session')
app.use(session({
    resave: false, //添加 resave 选项
    saveUninitialized: false, //添加 saveUninitialized 选项
    secret: 'secret key',
    cookie: {maxAge: 24 * 60 * 60 * 1000}
}));
//开放静态资源
app.use(express.static(path.join(__dirname, 'public')))
//设置模板的默认路径
app.set('views', path.join(__dirname, 'views'))
//设置模板的默认后缀
app.set('view engine', 'art')
//根据后缀设置渲染的模板引擎
app.engine('art', require('express-art-template'))
//拦截所有请求对请求体进行封装
app.use(bodyParser.urlencoded({extended: false}))
//错误处理中间件
app.use((err, req, res) => {
console.log(err)
})
//监听端口
app.listen(80)
console.log('服务器启动完成')

  • express路由模块:
const express = require('express')
const admin = express.Router()
//渲染登录页面
admin.get('/login',(req, res) => {
    res.render('admin/login')
})
//用户登录操作
admin.post('/login', async (req, res) => {
    let {email, password} = req.body
    if (email.trim().length === 0 || password.trim().length === 0)
        return res.status(400).render('admin/error', {msg: '邮件地址或密码错误!'})
    let user = await User.findOne({email})
    if (user) {
        if (!bcryptjs.compareSync(password, user.password)) {
            res.status(400).render('admin/error', {msg: '邮箱地址或密码错误,三秒后返回登录页面'})
        } else {
            //保存用户在session中
            req.session.username = user.username
            //把用户给其他模板
            req.app.locals.userInfo = user
            template.defaults.imports.userInfo=user
            //保存用户角色到session
            req.session.role=user.role
            if (user.role==='admin'){
            res.redirect('/admin/user?page=1')
            }else {
                res.redirect('/home/')
            }
        }
    } else {
        res.status(400).render('admin/error', {msg: '邮箱地址或密码错误,三秒后返回登录页面'})
    }
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值