在写这篇文章之前,我花了很长时间在网上寻找对新手友好的node.js+mongoDB入门教程。这方面的教程非常多,但是对于一个新手并不友好,这篇文章的目的,就是让一个小小白也能一步步实现使用node+mongoDB创建一个属于自己的服务端,那么我们的全栈之路就从这里开始吧
git地址 https://github.com/foreverway/node-express-mogoDB.git
Node.js 是什么
作为一门服务端语言,node.js使用js的语法,但不代表就可以直接上手使用。当我们打开node.js的官方文档,会发现它着重介绍的是node的特性和api
作为一个称职的新手,我猜你会在十分钟之内关闭这个网页。因为学习是一个渐进的过程,我们通过框架从一个简单的demo入手,慢慢了解node.js会比较好。因为很多特性,包只有在使用的时候才会理解,一开始就学太多陌生的新事物,会让人无所适从 框架很多,一方面我们要快速上手,另一方面也要保留原语言的特性,过度封装的框架,可能反而不利于我们对node的理解,市面上有express,egg.js.next.js等,在这里,我选express入门
使用命令行安装express框架,初始化项目。打开express文件夹,建立一个js文件,比如server.js
在server.js文件中,引用express
const express = require('express) //require是CMD规范,类似es6的import
const app = express() 执行express返回结果
//启动服务,监听一个端口3000的端口
app.listen(3000,()=>{
console.log('App 正在监听3000的端口')
)})
启动项目 node server (server.js的后缀可以省略)
但是现在这个端口不会有什么反应,有过数据请求经验的会知道,我们一般会使用get方法请求数据,所以我们写一个关于get方法的定义,接收两个参数,第一个是路径,第二个是一个函数
app.get('/',function(req,res){
res.send('hello') //response,请求的时候,响应一个hello字符
})
第一个参数就是别人请求的路径,在这里就是根路径
访问http://localhost:3000/
这看起来似乎没感觉,那把send输出的值换成一个对象数组
[{name:'朝夕',provience:'广东'}, {name:'xiaomi小明g',provience:'台湾'}] //重启一次server node server
我们从后端请求的数组数据就是这样的,这时候你可能会觉得每次改都重启太麻烦了,所以这时候我们换成nodemon(nodemon server)来启动,这样他会自动监听我们的修改。知道了这些,我们可以尝试写更多的接口
app.get('/',function(req,res){
res.send([{name:'朝夕',provience:'广东'},
{name:'小明',provience:'台湾'}
])
})
app.get('/shoppingList',function(req,res){
res.send([{id:'1',provience:'Gift A'},
{id:'2',provience:'Gift B'},
{id:'3',provience:'Gift C'}
])
})
app.get('/home',function(req,res){
res.send('this is my home')
})
这样当我们访问 http://localhost:3000/home
这样当我们访问 http://localhost:3000/shoppingList
托管静态文件
通过上面的方法,我们可以对用户访问网址做出响应,但我们有时候想访问其他页面的内容怎么办呢,这时候我们就需要实现一个路由
app.use(express.static('public'))
我们在server.js中添加这个中间件,他专门用来做静态文件的托管,我们使用这个可以访问到public路径下的文件
新建一个public文件,然后新建一个index.html,随便写点什么
2·访问http://localhost:3000/index.html
3·当然,我们也可以放在其他路径,app.use()的默认路径是根路径,我们也可以自己设置路径,
app.use('/static',express.static('public'))
这时候就需要去http://localhost:3000/static/index.html才可以访问到
处理跨域
我们先在刚刚public创建的index.html文件请求刚刚创建的数据
fetch('http://localhost:3000/shoppingList').then(res=>res.json()
//将数据转化为json格式
).then(res=>{
console.log(res)
})
打开http://localhost:3000/static/index.html,在Network可以看到收到的数据
一切看起来很完美,因为我们这里是同域名,端口,协议。不会有跨域的问题
如果在刚刚的步骤,有同学使用了open with live server
这个插件,他会基于本地的ip地址,打开
这个网页,顺便
没错,老朋友跨域是不会缺席的,因为这时候我们的域名和协议都改变了,我们应该都知道跨域的解决办法,最常用的就是nginx反向代理和CORS添加允许跨域的请求头
在express中,使用CORS更加简便,有相应的npm包协助我们处理这件事情
cnpm i cors -S
然后在server.js中,引用cors
app.use(require('cors')())//直接使用这个模块,回头看,跨域就被解决了..
连接数据库 mongoDB
虽然我们已经可以在前端页面获取node.js生成的数据,但这样每次数据的变动都要手动更改,这样只适合自己纯展示的 mock数据,日常开发,我们的数据都会放在数据库中,数据库不是什么高大上的概念,就我认为 只是一个存放数据的仓库,我们可以通过增删改查语句来查询我们想要的数据 在node中用的比较多的是mongoDB,数据库也有本地的和线上的,当我们没有自己的云服务期的时候,我们只能将数据放在本地 这样就只有自己可以获取到,有自己云服务器的可以放到上面
我们在这里简单讲一下mongoDB,首先自己在官网下载 下载之后,我们需要下载一个在node.js中连接数据库的包 mongoose
npm i mongoose -S
链接数据库 同样的 我们需要在server.js中引入这个包
const mongoose = require('mongoose')
mongoose.connect('mongoose://localhost:27017/ShoppingList')
//第一个参数是数据库的地址,他的格式是mongoDB://开头+数据库的ip地址+端口号默认27017+/
//如果起的是不存在的数据集合,则会自己给你创建
//ShoppingList表明我们连接ShoppingList这个数据集合
在这里我们是本地的数据库所以地址就写localhost或者127.0.0.1
填好之后我们启动,他会报一个错,因为缺少一些参数,我们根据提示,加上
const mongoose = require('mongoose')
mongoose.connect('mongodb://localhost:27017/ShoppingList',
{ useNewUrlParser: true ,useUnifiedTopology:true} )
链接数据库的代码就是这样
接下来我们需要定义模型(在mongoDB称为集合),也就是对数据库的数据分类,每个模型里面是我们对应的数据 比如我们现在有一个购物列表(shoppingList)的模型,我们需要这样定义
const shoppingList = mongoose.model('ShoppingList',new mongoose.Schema({title:String}))
# 第一个参数为模型的名称,一般首字母需要大写
# 第二个参数是表结构,然后接受一个对象作为参数,比如有title属性,他的值是值的类型,比如String
这样我们就可以先使用了,我们先把刚刚写死的ShoppingList的接口连上数据库
app.get('/shoppingList',async function (req, res) {
res.send(await ShoppingList.find())
find()没有限制查询条件,意思是查找所有数据
这里因为连接数据库是一个异步操作我们这里使用async和await能够同步的获取我们数据库得值
})
当然因为数据库里没有数据,所以我们可以临时插入一些数据便于观察, 我们在这个接口下面写一个
ShoppingList.insertMany([{title:'电脑1'},{title:'电脑2'},{title:'电脑3'},])
通过insertMany(插入多条)我们就往数据库插入了后面的数据,保存,看下效果。 如果你多次保存,执行的话会发现,数据越来越多了,因为这个插入语句是会重复执行的 所以我们可以插入之后将他注释掉
访问连接地址,就可以看到我们刚刚插入的数据。多出来的_id表示每一个值的标识是自动生成的,__v表示数据的版本
mongoDB查询
刚刚我们已经对数据库的数据进行过查询,但是很明显工作中需要的很多,比如有分页,有要查询特定条件的值
我们这里改变刚刚的查询条件
app.get('/shoppingList',async function (req, res) {
// const data = await ShoppingList.find().limit(2)
//limit 就像他的意思,限制条数我这里是2条,其实在vscode中,安装好mongoDB的插件,会自动提示find()的方法
const data = await ShoppingList.find().skip(1).limit(2)
//skip 跳过,这里就是显示2.3,跳过1。他们这两个结合就用来做分页
// const data = await ShoppingList.find().where({
title:'电脑1'})
//这个就是只查询title等于电脑1的数据
//sort(_id:1/-1)排序,-1表示倒叙
res.send( data )
也常常有这种需求,就是查看一个商品的详情,这时候我们可以提供一个专门的接口返回数据
app.get('/shoppingList/:id',async function (req, res) {
//# :表示后面可以是任意字符
const data = await ShoppingList.findById(req.params.id)
//findById这里的id就是我们从url里获取的,req表示客户端请求的参数
//req.params表示客户端传递过来的所有参数
res.send( data)
//res表示服务端相响应的数据
})
就像下面这样
mongoDB编写新增产品和上传的post请求 你刚刚可能注意到了,我们所有的接口都是使用get方法进行的,但有时候我们需要发送一些比较大的数据,不适合通过url发送,这时候就需要使用POST方法 //添加数据到列表接口 //我们刚刚使用代码的insertMany方法插入数据,现在使用post来完成
app.post('/shoppingList',async function (req, res) {
const data = {}
//上传一个空对象
res.send( data)
})
现在去原来的页面请求这条数据
会发现还是访问原来的get接口,因为他们的地址是一样的,这里我们在vscode里下载一个扩展
rest client
他帮助我们使用代码来发起不同类型的http请求
下载完成之后,我们在根目录下新建一个文件,名字随意,但是后缀需要是http
我们先使用get方法 加上我们刚刚的链接
get http://localhost:3000/shoppingList
这时候上面会出现Send Require 我们点一下,在右边就可以看到服务端返回的信息
那我们有多个接口怎么写呢
首先多个接口要用### 分开,然后我们可以定义公共的部分,不用每次都写
像这样,可以看到我们返回回来的结果是空的,因为我们刚刚发送的也是个空对象 //我们知道数据有很多种类型,如果前后端规范不一致 //就会报415的错误,所以在这里我们需要对数据类型进行规范
Content-Type:application/json 记得要紧接着post命令行写
//如果使用axios那样的库就不需要自己加 //我们规定这里发送JSON格式的数据,记得json是双引号 然后使用这个post发送一条数据试试
哎?数据怎么还是没有出现。 因为我们虽然在这里提交,但是服务端并没有接收,我们对刚刚的server.js页面 改写post请求
app.post('/shoppingList',async function (req, res) {
const data =req.body
//req.body。了解post请求的会知道,post请求的主体是body,
//req.body表示客户端提交过来的数据,
res.send( data)
})
试一下,还是没有返回任何数据,因为express默认没有开启对JSON文件的解析
我们需要在server.js里const app = express()
后的任何位置加上
app.use(express.json()))
表示我们允许他解析提交过来的jsop格式的数据
再试一次,发现可以获取到post的数据
做了这么多,只是铺垫,我们回到标题:怎么把post的数据存入数据库
首先排除
connect.http
,这里只是模拟客户端发送数据,相当于用户上传的部分,这里我们是没办法接触数据库的,只能在服务端进行,也就是我们对应的post请求里
改写post请求
app.post('/shoppingList',async function (req, res) {
const data = req.body
const shopping =await ShoppingList.create(data)
//获取到客户端发送的值之后,创建数据使用create存入ShoppingList集合,记得使用await
res.send( shopping)
})
在发送试一次
存入数据库成功
设置查询数据库接口为查询所有
//查看列表接口
app.get('/shoppingList',async function (req, res) {
const data = await ShoppingList.find()
res.send( data)
})
点击Send request
数据已经存入了数据库 其他类型的请求 一般的,我们使用get获取数据,post发送数据,在修改的时候我们会使用put提交我们的请求 这里就分析一下如何使用put。 其实put和查看详情的接口有一定的相似之处,因为我们都是先通过id等属性 找到某条数据数据,在进行操作
//修改详情接口
app.put('/shoppingList/:id',async function (req, res) {
//put表示覆盖,patch表示部分修改
const data = await ShoppingList.findById(req.params.id)
data.title = req.body.title
//根据客户端传入的值修改
await data.save() //保存修改
res.send( data)
})
然后在connect.http文件,我们写上put接口
PUT {{uri}}shoppingList/5f53bb006e15a80b2c4bdb7c
Content-Type:application/json
{
"title":"电脑1010"
}
//然后查看产品数据库列表
可以看到,数据库里的值已经修改成功 类似的,我们也可以很容易得到删除的写法
//删除一个数据
app.delete('/shoppingList/:id',async function (req, res) {
const data = await ShoppingList.deleteOne({id:req.body.id}
res.send( data)
})
connect.http
DELETE {{uri}}shoppingList/5f538c6054c5512be4876208
Content-Type:application/json
就是这样,执行之后,你同样发现数据库的这条数据已经被删除了
vue项目连接数据库
到现在,我们的基础工作就做到这里,那么在实际项目怎么使用呢
下一篇文章会讲到那些
参考来源