本节知识点
注意:这里是基于文件,而不是数据库;CRUD为增删改查
crud是指在做计算处理时的增加(Create)、读取(Retrieve)、更新(Update)和删除(Delete)
大纲
(1)复习
(2)文件操作路径'/'与模块标识路径'/'
1、文件操作路径
2、模块标识路径
注意:这里.js后缀可以直接省略
这里可以直接传参调用
3、分析先后顺序
结果为先输出模块读取结果,后输出文件读取结果,原因分析如下
所有文件操作的API都是异步的,类似于ajax请求
4、路径以/开头
文件操作下以/开头,表示磁盘根路径
5、小结
注意: 文件操作路径可以省略./,读取同级文件 模块操作路径不可省略./ 文件操作路径和模块操作路径如果以/开头,则都是读取磁盘根路径
(3)Express-helloworld案例
1、新建项目目录express-demo
2、使用指令创建package.json项目说明文件
npm init [--yes]
3、参照package.json中的main选项,新建入口执行文件index.js
4、下载安装第三方模块npm i express --save(模块后面不加版本默认下载当前最新版)
5、开始编写index.js入口文件脚本
启动服务器,监听端口
添加响应处理,设置请求处理函数
原生的API依旧可以使用
对比: express可以直接使用res.send()方法返回响应,且无需处理请求头Contype-Type类型 原生语法需要针对不同响应内容,对应处理其请求头Contype-Type类型
6、并行路径处理
相对于原生的if...else if...else判断处理路径,这里可以直接并行处理,更加简洁直观
(4)nodemon工具自动重启服务
目前为止编写完代码后都需要重启一次服务才可以使用,接下来利用第三方模块nodemon工具即可自动重启服务
注意:
在任意目录执行安装该模块命令都可以,也就是说,说有需要 --global来安装的包都可以在任意目录位置执行命令进行安装
检测是否安装成功
nodemon --version或者nodemon -v,如下所示
接下来通过nodemon启动服务
node index.js替换为nodemon index.js
至此,以后便不用再频繁重启服务器来查看效果
以后每次Ctrl+S保存代码,便会自动重启一次
(5)Express中static-server静态资源服务
1、开放某些公共静态资源
正常情况下,无法和Apache服务器一样,直接通过路径访问资源
接下来配置静态资源目录
2、相关
3、其他写法
①省略第一个参数,简化路径操作
②别名设置
这里重命名为static,此时便可以使用/static/来替代/public/
同理,也可以设置其他别名
4、小结
一般开发推荐设置别名为静态文件目录名
如果不加别名设置则可以直接在url后加上文件名访问
(6)基本路由
路由介绍
作用:实现资源分发处理
开发一般会编写到路由映射表
(7)Express中使用模板引擎art-template
接下来将之前的反馈系统重做一遍,利用Express框架
1、将之前的public和views文件拿到该项目目录下
2、开放静态资源
3、Express中配置使用art-template
4、配置(查看官方文档):
5、 使用模板引擎渲染
接下来测试下
这里第二个参数为可宣传参数,如果没有模板替换数据,则可以不写
接下来看下效果
此时发现无法预览,原因:后缀默认必须为art才可以
之所以改后缀名为art,更好辨识该模板要被template渲染。但这样会造成编辑器IDE无法高亮识别代码
另外,如果不想修改为art,可以修改配置
6、如果为嵌套于子目录的模板,则按照目录结构依次读取
7、传递替换数据
8、视图渲染存储目录
修改views默认模板存储目录
Express有个默认约定:开发人员将视图模板放置到views目录下,如果想修改可以通过如下API
9、配置使用小结
(8)Express留言板案例
1、代码
var express = require('express') var app = express() /*开放静态资源*/ app.use('/public/',express.static('./public/')) /*配置使用art-template模板引擎*/ app.engine('html',require('express-art-template')) /*修改默认(视图渲染存储目录)模板文件存放目录 加入将views目录放到public下的views,则可以修改如下 */ app.set('views','./public/views') /*路由*/ var comments = [ {name:'tony',message:'你好tony,感觉人生达到了巅峰',dateTime:'2016-02-12'}, {name:'bob',message:'你好bob,感觉人生达到了巅峰',dateTime:'2016-03-02'}, {name:'jack',message:'你好jack,感觉人生达到了巅峰',dateTime:'2016-11-18'} ] app.get('/',function(req,res){ res.render('index.html',{ comments:comments }) }) app.get('/post',function(req,res){ res.render('post.html') }) app.get('/pinglun',function(req,res){ var comment = req.query comment.dateTime = '2017-11-11' comments.unshift(comment) /*Express重定向API*/ res.redirect('/') /* res.statusCode = 302 res.setHeader('Location','/') res.end()结束响应 */ }) app.listen(3000,function(){ console.log('app is running at port 3000...') })
这里注意:“使用Express框架后,不再需要设置状态码302,然后通过响应头重定向”,这里借用重定向API---res.redirect()
(9)Express中post请求
表单提交数据时最好使用post请求,所以接下来使用post请求测试下
1、前言
因为原生node实现post请求较为繁琐,一般开发时不自行编写post。
这里使用express框架封装好的post请求去进行交互
2、post方式处理表单请求
①首先将表单提交方式改为post
②编写post响应,测试数据
由下面可以分析出可以利用不同的请求方法(post、get),让一个请求路径(/pinglun)可以使用多次
此时提交表单数据时,服务器便会做出对应处理,如下所示
③响应处理步骤
④获取post请求头数据
req.query方式只能获取get方式请求数据
因为post方式请求数据会将数据放到请求头里
⑤获取post请求数据
Express没有封装解析表单post请求体数据的API,所以这里要借助插件--middleWare中间件
其中body-parse便是专门用于解析表单post请求体
3、body-parse第三方包使用步骤
安装后结合文档配置好即可,具体配置步骤不用记忆
4、body-parse第三方包使用
①下载
②配置body-parser中间件
③测试
此时便可以获取post请求体数据,接下来可以做下一步处理
④获取并处理数据,重定向
⑤完整代码
var express = require('express') var bodyParser = require('body-parser') var app = express() /*开放静态资源*/ app.use('/public/',express.static('./public/')) /*配置使用art-template模板引擎*/ app.engine('html',require('express-art-template')) /*修改默认(视图渲染存储目录)模板文件存放目录 加入将views目录放到public下的views,则可以修改如下 */ app.set('views','./public/views') /*配置body-parse请求体第三方包*/ app.use(bodyParser.urlencoded({extended:false})) app.use(bodyParser.json()) /*路由*/ var comments = [ {name:'tony',message:'你好tony,感觉人生达到了巅峰',dateTime:'2016-02-12'}, {name:'bob',message:'你好bob,感觉人生达到了巅峰',dateTime:'2016-03-02'}, {name:'jack',message:'你好jack,感觉人生达到了巅峰',dateTime:'2016-11-18'} ] app.get('/',function(req,res){ res.render('index.html',{ comments:comments }) }) app.get('/post',function(req,res){ res.render('post.html') }) app.post('/pinglun',function(req,res){ var comment = req.body comment.dateTime = '2017-11-11' comments.unshift(comment) /*Express重定向API*/ res.redirect('/') }) /*这里已经无效,不过可以看出一个路径可以使用多种方法进行操作*/ app.get('/pinglun',function(req,res){ var comment = req.query comment.dateTime = '2017-11-11' comments.unshift(comment) /*Express重定向API*/ res.redirect('/') /* res.statusCode = 302 res.setHeader('Location','/') res.end()结束响应 */ }) app.listen(3000,function(){ console.log('app is running at port 3000...') })
⑥小结
所以不用加res.end()手动结束
(10)crud起步
1、在开始新项目之前首先创建好基础目录
①新建项目目录curd-code
②创建package.json
③创建说明文件中main选项对应的入口执行文件index.js
④创建默认视图渲染存储目录views
⑤创建静态资源开放目录public
⑥下载安装第三方模块
2、读取响应结果,返回index.html页面
结果如下
这里发生报错,原因在于没有安装和配置模板引擎
3、安装配置模板引擎
此时再次验证,结果如下
4、编辑html模板
使用服务端不用太关注样式,所以找个模板直接套过来用
这里去bootstrap官网找个模板过来直接使用
然后将模板代码复制到index.js
接下来修改模板相关资源
5、修改模板文件
①因为该模板依赖bootstrap,所以下载bootstrap包
②引用bootstrap资源
因为bootstrap模块下载到了node_modules目录,所以这里需要开放node_modules目录
接下来修改引入资源路径
③自定义样式表
这里IE10兼容样式表可以先去掉
自定义样式表dashboard.css,去官网拔取即可,拔取后放到public开放资源目录下
再往下,兼容IE9的代码暂时除去
底部的jQuery暂时不用,也去除
接下来做个循环测试下
接下来开始制作持久化存储,在介绍数据库前,首先将信息存储到文件
(11)文件读取数据(操作文件)
1、创建
项目根目录下创建db.json,存放基本数据
一般都有id标识,gender性别0为男,1为女
之所以不让用“男女”去标记存储,是因为0和1占用的控件更小一些
接下来写入基本存储数据,如下所示
{ "students":[ {"id":1,"name":"张三","gender":0,"age":18,"hobby":"游戏"}, {"id":2,"name":"张四","gender":0,"age":16,"hobby":"代码"}, {"id":3,"name":"张五","gender":1,"age":18,"hobby":"电影"}, {"id":4,"name":"张六","gender":1,"age":23,"hobby":"音乐"}, {"id":5,"name":"张七","gender":0,"age":25,"hobby":"爬山"}, {"id":6,"name":"张八","gender":1,"age":24,"hobby":"游泳"}, {"id":7,"name":"张九","gender":0,"age":26,"hobby":"跳舞"}, {"id":8,"name":"张十","gender":1,"age":22,"hobby":"弹琴"} ] }
之后将该文件数据渲染至index.html
2、修改遍历index.html文件
接下来首先在index.js里写个students做个测试
结果如下
3、读取文件数据
注意:Express框架没有提供读取文件相关操作,所以这里需要使用原生fs
验证如下
4、字符解析
接下来解析字符即可
注意:文件读取信息出来是字符串,需要再次转化即JSON.parse(data)才可以
(12)小结
(13)crud路由设计
针对项目简单写个设计文档
1、路由模块提取
项目根目录下新建路由配置文件router.js
然后将路由配置相关内容放置router.js
而index.js入口文件作用只是:启动服务器、配置相关信息
2、非正式方法
先来个简单测试,这里将index.js中的模块导出,然后在路由文件引入,接着启动路由文件。因为路由文件里导入了index.js,所以仍然可以正常启动
接下来启动服务器
测试后可以正常访问。
但此时入口文件已经不再是index.js而是router.js,这种非正式方式不推荐使用
3、合理提取
导出方法后,在入口文件引入调用,这种方法较之前来说较为合理,但也不方便,Express提供了一种更好方式
4、Express包装路由
Express包装路由步骤 1、创建路由容器router 2、将路由挂载至router容器 3、导出容器router
接下来将express框架创建的路由容器router挂载到app服务实例中
此时入口文件作用如下
路由文件作用如下
处理路由;根据不同的请求方法+请求路径,设置具体的请求函数
注意:
模块职责要清晰,不可混用
划分模块的目的就是为了增强代码的可维护性,提升开发效率
(14)处理添加页面+配置body-parse中间件
首先修改下路由文件配置,结合路由设置文档,如下
1、新建new.html文件写入内容,这里直接去bootstrap官网引用表单
接下来设置路由信息,查看效果
2、修改链接,点击跳页
3、完善学生信息表单
注意:
表单name值必填项
4、接下来开始服务配置
1、获取表单数据 2、处理 3、发送响应
因为是post请求,而express里没有获取post请求的API,结合之前步骤,开始安装配置
注意:配置模板引擎和body-parse中间件,一定要在挂载路由实例之前(中间件的执行流程,由上至下)
5、获取表单数据
上面配置完post请求数据中间件后,开始进行测试。利用req.body获取。
这里可能会有小问题
这里只需要将body-parse中间件解析配置中的false改为true即可
验证如下:
点击提交后,服务器接收打印信息
这里注意表单的name作用:name 属性用于对提交到服务器后的表单数据进行标识
注意:只有设置了 name 属性的表单元素才能在提交表单时传递它们的值。
简单来说,name就是提交到后台的索引,比如在复选框中都要设置成name="hobby"说明几个复选框都在爱好下。
此时,服务器接收到输入信息
6、获取表单数据后,开始数据处理,保存至db.json用以持久化
做法: 首先读取文件信息--字符串,转换为对象,然后添加新增学生信息,最后再转为字符串存到json文件
即字符串→对象→字符串
(15)封装提取student数据操作模块
新建student.js文件封装增删改查的相关API,只处理数据,不关心业务(处理表单数据...等业务)
1、获取所有学生列表
这里需要用到fs核心模块
但有个问题,fs文件操作模块为异步操作,这里需要结合回调函数去获取文件数据
修改如下
接下来注释find
接下来做下测试,修改之前路由映射文件中读取文件操作
此后,如果再有其他地方需要用到student学生数据,只需要加载student模块,调用student.find()自定义API即可
里面只关心数据,没有业务逻辑
(16)封装异步API
详见下节文章
(17)封装保存学生的API
最终调用形式如下
1、分析
同理,与之前类似,保存学生信息前需要先读取文件,所以可以将之前读取操作直接copy过来,再加以修改
2、保存数据
接下来还需要添加学生id
这里注意:id可以理解为学生的身份证,必须具有唯一性;且就算后期被删除,新添加的人也不可能继承之前删除(去世)人的身份证号码,这里先进行简单处理
添加id方法,找到最后一个id,然后加1即可
3、保存的API已经完成,接下来开始调用API,实现存储
完整如下
此时便实现了数据的持久化存储,因为此时的数据已经存储到了json文件
以上便是异步编程,node核心
(18)回调函数
获取异步数据
(19)编辑学生页面
根据ID来更新
1、首先第一步,又需要读取文件
遍历查找对应数据
ES6语法:find查找遍历
2、查找到具体数据后,开始修改
常用的简单修改,一次重新赋值,如下所示
但这种过于累赘,直接使用for..in循环(遍历拷贝对象)即可
3、接下来将新对象转为字符串,再进行存储
4、接下来调用API进行测试
在路由配置文件,进行测试。 此时访问localhost:3000/students/edit便可以成功修改更新数据
5、编写更新页面(静态部分)
与之前新增页面类似,所以这里直接复制过来加以修改,然后设置路由配置
测试如下
6、添加编辑按钮,进行跳转
此时鼠标悬停时左下角便可以对应显示
7、接下来开始进行渲染
首先需要获取点击的id
接下来使用模板引擎进行定向渲染,因为需要根据id获取学生信息,所以接下啦再来封装一个API用来查找单个学生
8、查找单个学生API
做下测试调用
然后点击某个需要编辑的学生,查看服务器输出内容,此时发现可以正常获取所选信息
最后进行渲染
接下来编辑静态模板部分
注意:这里需要用到art-template的条件语句,查看文档如下
同理,修改下首页的性别显示,按照0男1女的格式设置
结果如下
(20)更新功能
1、点击提交按钮时,完成提交
表单的action和method已经写出,接下来设置路由即可
接下来添加id标识
注意:这里便用到了type=hidden,即不希望被客户看到,但需要被提交到服务器的内容
提交测试下,可以正确获取新内容
2、第一步获取已经完成,接下来调用API进行更新
接下来修改个人信息后,点击提交测试下,发现报错
分析:传过来的id为字符串,所以需要进行转换,或者直接将===改为==,不判断类型(之前也有多出需要修改);或者依次手动转换
(21)删除功能
1、首先获取要删除的id
此时点击删除便可以在控制台获取对应id
2、根据id进行删除操作,所以接下来封装删除API,API只负责数据操作,不管业务逻辑
然后进行调用,编写对应业务逻辑
同理传入回调函数,回调函数参数为error
如果失败则存在error,如果成功则error为null
3、编写删除API
首先删除对应元素
删完后,将students重写进去
接下来做下测试,调用API
完整代码如下
至此便可以实现删除功能
接下来可以添加确认框,提高用户体验,防止误操作
如下所示:
(22)总结
模块化思想:模块思想要单一
.