项目虽然不大,但在里面蕴含的知识点还是蛮多的,通过此项目,你可以进一步了解到前后端的数据发送。
一、功能概述
在此项目里,要实现的功能有:
1.getAllContact 获取全部联系人=>返回一个联系人数组,用户ajax请求后填充页面 get
2.search 搜索联系人 get
3.addContact 添加联系人 post
4.removeContat 删除联系人 get
5.reviseContact 修改联系人 post
二、利用express模块,实现后端服务器的搭建
1.就从简单的模块引用说起吧,首先我们要引入express模块,直接开启我们的终端(ctrl+`),键入npm init(-y)生成我们的package.json 和package-lock.js文件,接下来npm install express --save 这里要注意的是–save不要忘记写(方便日后项目的迁移),由于我们要处理post请求,所以我们还需要引入一个body-parser模块,指令如下:npm install body-parser --save。最后是我们的mongodb(多说一句,mongodb因为其为轻量级数据库,操作语句简单,经常被用来完成小项目的实现),语句为:npm install mongodb --save.
2.为了程序的模块化,我们首先对mongodb的操作语句用node.js进行封装:
首先我们要引入mongodb模块,并初始化一些内容(这些都是固定操作):
const mongodb = require('mongodb')
const MongoClient = mongodb.MongoClient
const mongoUrl = 'mongodb://localhost:27017'
接下来我们就要建立连接啦,无论是什么操作,都基于此语句下:
MongoClient.connect(mongoUrl, { useUnifiedTopology: true }, (err, client) => {
if (err) {
console.log(err)
return
} else {
// 选库
var db = client.db('xinKu')
// 选表
var xinBiao = db.collection('xinBiao')
//具体操作语句.......
}
对于mongodb数据库的原生增删改查语句如下:
①增: insertOne 插入一个对象 第一个参数是对象
insertMany 插入一个数组。第一个参数是数组
xinBiao.insertMany([{name:'sss'},{name:"sss"}],(error,final)=>{
if(error){
console.log(error)
return
}else{
console.log(final.result)
client.close()
}
})
②删:deleteOne 默认删除第一个
deleteMany 删除所有的
xinBiao.deleteOne({ name: "sss" }, (error, final) => {
if (error) {
console.log(error)
return
} else {
console.log(final.result)
client.close()
}
})
③改: updateOne 更新一个
updateMany 更新多个
xinBiao.updateMany({ name: "sss" }, { $set: { name: "www", age: 20 } }, (error, final) => {
if (error) {
console.log(error)
return
} else {
console.log(final.result)
client.close()
}
})
④查(经常封装为byid,这样查找更精确)
xinBiao.find({name:"sss"}).toArray((error,final)=>{
if(error){
console.log(error)
return
}else{
// final表示结果数组
console.log(final)
client.close()
}
})
至此,我想你已经大致了解了如何利用node.js操作mongodb,但我们要想实现项目,还是需要进一步的封装(注意点有几点:
1.利用const ObjectId=monggodb.ObjectId 实现id操作数据库
2.注意this指向问题
3.注意关闭数据库)
var MongControll = function (dataBaseName, formName) {
this.dataBaseName = dataBaseName
this.formName = formName
//封装方法时要有callback回调函数,方便我们了解处理的结果
this.insertOne = function (newData, callback) {
MonggoClient.connect(monggoUrl, { useUnifiedTopology: true }, (err, client) => {
if (err) {
console.log(err)
return
}
var db = client.db(this.dataBaseName) //由于用了this,所以要用es6的语法,这样才能指向上层的this
var form = db.collection(this.formName)
form.insertOne(newData, (err, final) => {
if (err) {
console.log(err)
return
}
if (callback) { //如果有callback 我们就返回运行的结果
callback(err,final.result)
}
else {
console.log(final.result) //没有直接打印出来结果
}
client.close() //所有操作完毕必须关闭数据库
})
})
}
this.insertMany = function (newDataArr, callback) {
MonggoClient.connect(monggoUrl, { useUnifiedTopology: true }, (err, client) => {
{
if (err) {
console.log(err)
return
}
else {
var db = client.db(this.dataBaseName)
var form = db.collection(this.formName)
form.insertMany(newDataArr, (error, final) => {
if (error) {
console.log(error)
return
} else {
if (callback) {
callback(error,final.result)
} else {
console.log(error,final.result)
}
client.close()
}
})
}
}
})
}
// 删除语句的封装
this.delete = function (deleteObj, callback) {
MonggoClient.connect(monggoUrl, { useUnifiedTopology: true }, (err, client) => {
if (err) {
console.log(err)
}
var db = client.db(this.dataBaseName)
var form = db.collection(this.formName)
form.deleteOne(deleteObj, (error, final) => {
if (error) {
console.log(error)
return
}
if (callback) {
callback(error,final.result)
}
else {
console.log(final.result)
}
client.close()
})
})
}
this.deleteMany = function (deleteObjArr, callback) {
MonggoClient.connect(monggoUrl, { useUnifiedTopology: true }, (client, err) => {
if (err) {
console.log(err)
return
}
else {
var db = client.db(this.dataBaseName)
var form = db.connect(this.formName)
form.deleteOne(deleteObjArr, (error, final) => {
if (error) {
console.log(error)
return
}
if (callback) {
callback(err,final.result)
} else {
console.log(final.result)
}
client.close()
})
}
})
}
this.deleteById=function(id,callback)
{
MonggoClient.connect(monggoUrl,{useUnifiedTopology:true}, (err,client)=>
{
if(err)
{
console.log(err)
}
var db = client.db(this.dataBaseName)
var form = db.collection(this.formName)
form.deleteOne({_id:ObjectId(id)}, (error, final) => { //利用id传参数时,必须引用ObjectId()对id进行处理,否则会报错
if (error) {
console.log(error)
return
}
if (callback) {
callback(error,final.result)
}
else {
console.log(final.result)
}
client.close()
})
})
}
//查找语句的封装
this.find = function (findObj, callback) {
MonggoClient.connect(monggoUrl, { useUnifiedTopology: true }, (err, client) => {
if (err) {
console.log(err)
return
}
var db = client.db(dataBaseName)
var form = db.collection(formName)
form.find(findObj).toArray((error, final) => {
if (error) {
console.log(error)
console.log(1)
return
} else {
if (callback) {
callback(error,final)
} else {
console.log(final.length)
}
client.close()
}
})
})
}
this.findById=function(id,callback)
{
MonggoClient.connect(monggoUrl, { useUnifiedTopology: true }, (err, client) => {
if (err) {
console.log(err)
return
}
var db = client.db(dataBaseName)
var form = db.collection(formName)
form.find({_id:ObjectId(id)}).toArray((error, final) => {
if (error) {
console.log(error)
return
} else {
if (callback) {
callback(error,final)
} else {
console.log(final.length)
}
client.close()
}
})
})
}
//更新语句的封装
this.updateOne = function (updateObj, newdataobj, callback) {
MonggoClient.connect(monggoUrl, { useUnifiedTopology: true }, (err, client) => {
if (err) {
console.log(err)
}
else {
var db = client.db(this.dataBaseName)
var form = db.collection(this.formName)
form.updateOne(updateObj, { $set: newdataobj }, (error, final) => {
if (callback) {
callback(final.result)
}
else {
console.log(final.result)
}
// callback(final.result)
client.close()
})
}
})
}
this.updateById=function(id,newdataobj,callback)
{
MonggoClient.connect(monggoUrl, { useUnifiedTopology: true }, (err, client) => {
if (err) {
console.log(err)
}
else {
var db = client.db(this.dataBaseName)
var form = db.collection(this.formName)
form.updateOne({_id:ObjectId(id)}, { $set: newdataobj }, (error, final) => {
if (callback) {
callback(error,final.result)
}
else {
console.log(error,final,1)
}
client.close()
})
}
})
}
this.updateMany = function (updateObjArr, newdataobj, callback) {
MonggoClient.connect(monggoUrl, { useUnifiedTopology: true }, (err, client) => {
if (err) {
console.log(err)
}
var db = client.db(this.dataBaseName)
var form = db.collection(this.formName)
form.updateMany(updateObjArr, { $set: newdataobj }, (err, final) => {
if (err) {
console.log(err)
return
}
else {
if (callback) {
callback(err,final.result)
}
else {
console.log(final.result)
}
}
client.close()
})
})
}
}
至此,我们的模块就封装好了,接下来,将其导出
exports.MongControll = MongControll
3.利用导出的MongControll模块+express搭建服务器
在利用express模块搭建服务器首先引入我们需要的模块
const bodyParser = require('body-parser')
const express = require('express')
const app = express()
const unlencodeParser = bodyParser.urlencoded({ extended: true })
const MongoControll = require('./MongoControll').MongControll
var contact = new MongoControll('addressBook', 'list')//初始化一个数据库+表,存储数据
实现框架如下:
app.use(express.static('./static')) //引入静态文件 初始化页面
app.use(unlencodeParser) //为了post请求
app.get('url', (req, res) => {
.............
})
app.post('url', unlencodeParser, (req, res) => {
.......
})
app.listen(3000)
首先是获取全部联系人:
app.get('/getAllContact', (req, res) => {
contact.find({}, function (err, final) {
if (err) {
handle500(res)
return
}
else {
res.status(200).send(final)
}
})
})
2.删除联系人
app.get('/removeContact', (req, res) => {
var id = req.query.id
contact.deleteById(id, (err, final) => {
if (err) return handle500(res)
res.status(200).send(final)
})
})
3.修改联系人
app.post('/reviseContact', unlencodeParser, (req, res) => {
var { name, id, phoneNumber } = req.body
var docs = {
name: name,
phoneNumber: phoneNumber
}
// 方法一、先插入后删除
// contact.insertOne(docs, function (err, final) {
// if (err) {
// handle500(res)
// console.log('插入出错')
// return
// }
// contact.deleteById(id, (err, final) => {
// if (err) return handle500(res)
// res.status(200).send(final)
// })
// })
//方法二 直接利用update
contact.updateById(id,{name:name,phoneNumber: phoneNumber},(err,final)=>
{
if (err) return handle500(res)
res.status(200).send(final)
})
})
4.查找联系人
app.get('/search', (req, res) => {
var wd = req.query.wd
var reg = new RegExp(wd, 'i')
contact.find(
{
$or:
[
{ name: { $regex: reg } },
{ phoneNumber: { $regex: reg } }
]
}, (err, final) => {
if (err) {
handle500(res)
return
}
else {
res.status(200).send(final)
}
}
)
})
5.增加联系人
app.post('/addContact', unlencodeParser, (req, res) => {
var { name, phoneNumber } = req.body
var docs = {
name: name,
phoneNumber: phoneNumber
}
contact.insertOne(docs, function (err, final) {
if (err) {
return handle500(res)
}
res.send({ final: 'ok' })
})
})
三、jQuery+ajax实现前端数据请求
首先是获取全部联系人
$.ajax(
{
type: 'GET',
url: '/getAllContact',
data: {},
success: function (result) {
console.log(result)
// 获取到数据之后,填充数据
renderPage(result)
}
}
)
2.增加联系人
$.ajax(
{
type: 'POST',
url: '/addContact',
data: {
name: name,
phoneNumber: phoneNumber
},
success: function (result) {
//添加好联系人之后,获取所有联系人
getAllContact()
}
}
)
3.修改联系人信息
$.ajax(
{
type: 'POST',
url: '/reviseContact',
data: {
name: name,
id: id,
phoneNumber: phoneNumber
},
success: function () {
getAllContact()
}
}
)
4.查找联系人
$.ajax({
type:'GET',
url:'/search',
data:{
wd:wd
},
success:function(e)
{
renderPage(e)
}
})
5.删除联系人
var removeContact = function (id) {
// $.ajax(
// {
// type: 'GET',
// url: '/removeContact',
// data: { id: id },
// success: function (req, res) {
// console.log(id)
// getAllContact()
// }
// }
// )
$.ajax(
{
type: 'POST',
url: '/removeContact',
data: { id: id },
success: function (req, res) {
getAllContact()
}
}
)
}
此外,我们还要利用ajax实现页面的渲染,即将我们获取到的数据,填充到html页面中:
var renderPage = function (array) {
var html = ''
array.forEach(element => {
html += `
<li class="list-group-item">
<h3>${element.name}</h3>
<p>${element.phoneNumber}</p>
<div class="btn-group" role="group" aria-label="...">
<a type="button" href="tel:${element.phoneNumber}" class="btn btn-default">拨打号码</a>
<button type="button" class="revise-button btn btn-default" phone="${element.phoneNumber}" name ="${element.name}" data-_id="${element._id}">修改联系人</button>
<button type="button" class="remove-button btn btn-default" data-_id="${element._id}">删除联系人</button>
</div>
</li>
`
});
contactList.html(html)
addEventListner()
}
总结一下注意的一些点:
1.因为我们的css样式,有些功能是我们在点击按钮后才会弹出,所以我们要注意此类函数的实现,以及事件的监听,它是发生在我们填充完html之后的,所以获取元素要注意将此类事件封装到一个函数当中,在渲染函数后调用,而不是在全局直接获取此类元素 。
2.在修改联系人的时候要避免数据更新不及时而导致重复修改的问题,针对此点,我们要在revise监听器内,实现一个/getContact(它是利用id方法曲查找联系人),以便数据的更新
$.ajax(
{
type: 'GET',
url: '/getContact',
data: {
id: data_id,
},
success: function (e) {
console.log(e)
var nowRevise=e[0]
if(nowRevise)
{
reviseContactName.val(nowRevise.name)
reviseContactPhoneNumber.val(nowRevise.phoneNumber)
}
reviseModal.show()
}
}
)
3.前端功能的一些简单封装
class Modal{
constructor(jQueryDom,inputIdList)
{
this.dom=jQueryDom
this.inputList=[]
var me=this
inputIdList.forEach(function(e)
{
me.inputList.push($('#'+e))
})
}
show()
{
this.dom.modal('show')
}
hide()
{
this.dom.modal('hide')
}
resetInput()
{
this.inputList.forEach(function(e)
{
e.val('')
})
}
}
var reviseModal=new Modal(
$('.revise-modal'),
['revise-contact-name','revise-contact-phoneNumber']
)
四.html是利用bootstrap实现的,查看文档就好啦这里不再赘述(引入语句如下)
<script src="./js/jquery-2.1.0.js"></script>
<script src="./bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="./bootstrap-3.3.7-dist/css/bootstrap.min.css">
遇到的坑:利用id操作数据时一定要!!注意空格呀 千万不要手滑…因为这个原因找了半个小时的bug(也算长经验了)
五、实现页面如下
源码上传至Github,有需要者可以自行下载