Node.js学习笔记(四)

Express

文件操作路径和模块路径

文件操作路径:

// 在文件操作的相对路径中
// ./data/a.txt 相对于当前目录
// data/a.txt 相对于当前目录
// /data/a.txt 绝对路径,当前文件模块所处磁盘根目录
// c:/xx/xx... 绝对路径
fs.readFile('./data/a.txt', function(err, data){
    if(err){
        console.log(err)
        return console.log('读取失败')
    }
    console.log(data.toString())
})

模块操作路径:

// 这里如果忽略了. ,则是磁盘根目录
require('/data/foo.js')
1. 起步

安装:

npm init -y 初始化项目

npm install –save express

hello world:

var express = require('express');

// 1. 创建 app
var app = express();

app.get('/',function(req,res){
    // res.write('hello ');
    // res.write('world ');
    // res.end();
    // res.end('hello world');
    res.send('hello world !');
})

app.get('/login',function(req,res){
    res.send('login !');
})

app.listen(3000,function(){
    console.log('app is running port 3000');
});
2. 基本路由:

路由其实就是一张表,表里面有具体的映射关系。

  • 路由
    • 请求方法
    • 请求路径
    • 请求处理函数

get:

# 当你以GET方法请求/的时候,执行对应的处理函数
app.get('/login',function(req,res){
    res.send('login !');
})

post:

# 当你以POST方法请求/的时候,执行对应的处理函数
app.post('/',function(req,res){
    res.send('login !');
})
3. 修改完代码自动重启

我们这里使用一个第三方命令行工具:nodemon来解决频繁修改代码重启服务器问题。

nodemon是一个基于Node.js开发的一个第三方命令行工具,我们使用的时候需要独立安装

在任意目录执行该命令都可以:

npm install –global nodemon

nodemon –version

安装完毕之后,使用:

node app.js
# 使用nodemon
nodemon app.js

只要通过nodemon app.js启动的服务,则它会监视你的文件变化,当文件发生变化时候,自动帮你重启服务器。

4. 静态服务
// 当以/public/ 开头的时候,去./public/目录中找对应的资源
// 这种方式更容易辨识,推荐这种方式
// app.use('/public/',express.static('./public/'));

// 必须是/a/public目录中的资源具体路径,别名
// app.use('/a/',express.static('./public/'));

// 当省略第一个参数的时候,则可以通过省略 /public的方式直接访问
// 这种方式的好处就是可以省略 /public/
app.use(express.static('./public/')); 
5. 在Express中配置art-template

安装:

npm install --save art-template
npm install --save express-art-template

配置:

# 配置使用 art-template 模板引擎
# 第一个参数:表示,当渲染以.art结尾的文件时候,使用art-template模板引擎
# express-art-template是专门用来在Express中把art-template整合到Express中
# express-art-template 依赖了 art-template
app.engine('html', require('express-art-template'));

使用:

# Express 为 Response 相应对象提供了一个方法:render
# render方法默认是不可以使用,但是如果配置了模板引擎就可以使用了
# res.render('html模板名',{模板数据})
# 第一个参数不能写路径,默认会去项目中的views目录查找模板文件
# express有一个约定:开发人员吧所有的视图文件都放到了views目录中
app.get('/', function (req, res) {
    # express默认会去项目中的views目录中找index.html
    res.render('index.html', {  // 如果使用index.html格式的,应该将上面的art换成html
        user: {
            name: 'aui',
            tags: ['art', 'template', 'nodejs']
        }
    });
});

如果希望修改默认的views视图渲染存储目录,可以:

# 注意: 第一个参数不能写错
app.set('views',目录路径);
6. 在Express中获取表单GET请求参数

Express内置了一个API,可以直接通过req.query来获取

req.query

7. 在Express中获取表单POST请求体数据

在Express中没有内置获取表单POST请求体的API,这里我们需要使用一个第三方包:body-parser。

安装:

npm install --save body-parser

配置:

var express = require('express');
// 引包
var bodyParser = require('body-parser');

var app = express();

// 配置body-parser中间件(插件)
// 只要加入这个配置,则在req请求对象上会多出来一个属性:body
// 也就是说你就可以直接通过req.body来获取表单POST请求体数据了
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false}));
// parse application/json
app.use(bodyParser.json())

使用:

app.use(function(req,res){
    res.setHeader('Content-Type','text/plain');
    res.write('you posted:\n')
        // 可以通过 req.body 来获取表单POST请求提数据
    res.end(JSON.stringify(req.body,null,2))
})
8. Express - crud —— express中路由的使用

起步

  • 初始化
    • npm init -y
  • 安装相应的包和中间件
    • cnpm install –global nodemon
    • cnpm install express art-template express-art-template –save
    • cnpm install –save body-parser
    • cnpm install –save bootstrap@3.3.7
  • 开启静态资源
    • app.use(‘/node_modules/’, express.static(‘./node_modules/’))
    • app.use(‘/public/’, express.static(‘./public/’))
  • 模板处理

app.js

var express = require('express')

var bodyParser = require('body-parser');

var app = express()


app.use('/node_modules/', express.static('./node_modules/'))
app.use('/public/', express.static('./public/'))

app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json())

app.engine('html', require('express-art-template'));

app.get('/', function(req, res){
    res.render('index.html', {
        fruits: [
            '苹果',
            '香蕉',
            '橘子',
            '西瓜'
        ]
    })
})

app.listen(3000, function(){
    console.log('server running port 3000')
})

路由设计

请求方法 请求路径 get参数 post参数 备注
GET /students 渲染首页
GET /students/new 渲染添加学生叶页面
POST /students name,age,gender,hobbies 处理添加学生请求
GET /students/edit id 渲染编辑页面
POST /students/edit id,name,age,gender,hobbies 处理编辑请求
GET /students/delete id 处理删除请求

提取路由模块

router.js

/**
 * router.js 路由模块
 * 职责:
 *      处理路由
 *      根据不同的请求方法+请求路径设置具体请求函数
 *  模块职责单一,不要乱写
 *  我们划分模块的目的就是为了增强项目代码的可维护性
 *  提升开发效率
 */

var fs = require('fs')

// Express提供了一种更好的方式
// 专门用来包装路由的
var express = require('express');

var Students = require('./student.js')

// 1. 创建一个路由容器
var router = express.Router()
// 2. 把路由都挂载到 router 路由容器中

router.get('/students',function(req,res){
    // readFile 的第二个参数是可选的,传入utf-8就是告诉它把读取的文件直接按照utf8编码
    // 除了这样转换之外,可以通过data.toString()的方式
    /*
    fs.readFile('./db.json','utf8',function(err,data){
        if(err){
            return res.status(500).send('Server error.');
        }
        // console.log(data);
        var students = JSON.parse(data).students 
        res.render('index.html',{
            fruits: [
                '苹果',
                '香蕉',
                '橘子'
            ],
            students: students
        })
    })
    */
    Students.find(function(err, students){
        if(err){
            return res.status(500).send('Server error.')
        }
        res.render('index.html', {
            fruits: [
                '苹果',
                '香蕉',
                '橘子',
                '西瓜'
            ],
            students: students
        })
    })
})

router.get('/students/new',function(req,res){
    res.render('new.html');
})

router.post('/students/new',function(req,res){
    // 1. 获取表单数据
    // 2. 处理 将数据保存到db.json文件中用以持久化
    // 3. 发送响应
    //      先读取出来,转成对象
    //      往对象中push数据
    //      将对象转换为字符串
    //      然后把字符串再次写入文件
    //   console.log(req.body);
    Students.save(req.body, function(err){
        if(err){
            return res.status(500).send('Server error.')
        }
    })
    res.redirect('/')
})

router.get('/students/edit',function(req,res){
    // 1. 在客户端的列表页中处理链接问题(需要有id参数)
    // 2. 获取要编辑的学生
    // 3. 渲染编辑页面
    //      根据id把学生信息查出来
    //      使用模板引擎渲染页面
    Students.findById(parseInt(req.query.id), function(err, student){
        if(err){
            return res.status(500).send('Server error.')
        }
        res.render('edit.html',{
            student: student
        })
    })
})

router.post('/students/edit',function(req,res){
    // 1. 获取表单数据  req.body
    // 2. 更新  Student.update()
    // 3. 发送响应
    Students.updateById(req.body, function(err){
        if(err){
            return res.status(500).send('Server error.')
        }
        res.redirect('/')
    })
})

router.get('/students/delete',function(req,res){
    // 1. 获取要删除的id
    // 2. 根据id执行删除操作
    // 3. 根据操作结果发送响应数据
    Students.deleteById(req.query.id, function(err){
        if(err){
            return res.status(500).send('Server error.')
        }
        res.redirect('/')
    })
})

// 3. 把router导出
module.exports = router

app.js:

/**
*   职责:
*       创建服务
*       做一些服务相关配置
*           模板引擎
*           body-parser 解析表单post请求体
*           提供静态资源服务
*       挂载路由
*       监听端口启动服务
*/          

var express = require('express')
var fs = require('fs')
# var router = require('./router.js')

var bodyParser = require('body-parser');

var app = express()

app.use('/node_modules/', express.static('./node_modules/'))
app.use('/public/', express.static('./public/'))

# 配置模板引擎和body-parser一定要在app.use(router)挂载路由之前

app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json())

app.engine('html', require('express-art-template'));

// 把路由容器挂载到 app 服务中
# app.use(router)

app.listen(3000, function(){
    console.log('server running port 3000')
})

设计操作学生的API

student.js

/**
 * 数据操作文件模块
 * 职责:操作文件中的数据,只处理数据,不关心业务
 */

var dbPath = './db.json'
var fs = require('fs')

/**
 * 获取所有学生列表
 * return []
 */
exports.find = function(callback){
     fs.readFile(dbPath, 'utf8', function(err, data){
        if(err){
            return callback(err)
        }
        callback(null, JSON.parse(data).students)
    })
}

exports.findById = function(id,callback){
    fs.readFile(dbPath, 'utf8', function(err, data){
        if(err){
            return callback(err)
        }
       var students = JSON.parse(data).students
       var ret = students.find(function(item){
           return item.id === parseInt(id)
       })
       callback(null, ret)
    })
}

/**
 * 添加保存学生
 */
exports.save = function(student,callback){
    fs.readFile(dbPath, 'utf8', function(err, data){
        if(err){
            return callback(err)
        }
       var students = JSON.parse(data).students
        // 处理id唯一的,不重复
       student.id = students[students.length - 1].id + 1
        // 把用户传递的对象保存到数组中
       students.push(student)
       // 把对象数组转换为字符串
       var fileData = JSON.stringify({
            students: students
       })
       // 把字符串写到文件中
       fs.writeFile(dbPath, fileData, function(err){
           if(err){
               // 错误就是把错误对象传递给它
               return callback(err)
           }
           // 成功就没错,所以错误对象是null
           callback(null)
       })
    })
}
/**
 * 更新学生
 */
exports.updateById = function(student,callback){
     fs.readFile(dbPath, 'utf8', function(err, data){
        if(err){
            return callback(err)
        }
       var students = JSON.parse(data).students
       // 主意:这里记得把id同意转换为数字类型 
        student.id = parseInt(student.id)
       // 你需要修改谁,就把谁找出来
       var stu = students.find(function(item){
           return item.id === student.id
       })
       // 遍历拷贝对象
       for(var key in student){
            stu[key] = student[key]
       }

       // 把对象数组转换为字符串
       var fileData = JSON.stringify({
            students: students
       })
       // 把字符串写到文件中
       fs.writeFile(dbPath, fileData, function(err){
           if(err){
               // 错误就是把错误对象传递给它
               return callback(err)
           }
           // 成功就没错,所以错误对象是null
           callback(null)
       })
    })
}
/**
 * 删除学生
 */
exports.deleteById = function(id,callback){
    fs.readFile(dbPath, 'utf8', function (err, data) {
        if (err) {
            return callback(err)
        }
        var students = JSON.parse(data).students
        //    findIndex方法专门用来根据条件查找元素的下标
        var deleteId = students.findIndex(function (item) {
            return item.id === parseInt(id)
        })
        // 根据下标从数组中删除对应的学生对象
        students.splice(deleteId, 1)
        // 把对象数组转换为字符串
        var fileData = JSON.stringify({
            students: students
        })
        // 把字符串写到文件中
        fs.writeFile(dbPath, fileData, function (err) {
            if (err) {
                // 错误就是把错误对象传递给它
                return callback(err)
            }
            // 成功就没错,所以错误对象是null
            callback(null)
        })
    })
}
9. 自己编写步骤
  • 处理模板
  • 配置开放静态资源
  • 配置模板引擎
  • 简单路由:/students渲染静态页出来
  • 路由设计
  • 提取路由模块
  • 由于接下来一系列的业务操作都需要处理文件数据,需要封装student.js
  • 先写好student.js文件结构
    • 查询所有学生列表的API find
    • findById
    • save
  • 实现具体功能
    • 通过路由收到请求
    • 接收请求中的数据(get,post)
    • req.query
    • req.body
    • 调用数据操作API处理数据
    • 根据操作结果给客户端发送响应
  • 业务功能列表

    • 列表
    • 添加
    • 编辑
    • 删除

      1. 封装异步API

如果需要获取一个函数中异步操作的结果,则必须通过回调函数来获取。

function fn(callback){
    // var callback = function(data) {console.log(data)}
    setTimeout(function(){
        var data = 'hello'
        callback(data) // data实参数据
    },1000)
}
fn(function(data){
    console.log(data) // 形参数据
})
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值