MongoDB&Node.js学习笔记—用户信息增删改查案例
功能分析:
- 搭建网站服务器,实现客户端与服务器的通信
- 连接数据库,创建用户集合,向用户集合中插入文档
- 当用户访问/list时,将所有用户信息查询出来 (实现用户信息列表显示功能)
首先,实现路由功能
然后,呈现用户列表页面
最后,从数据库中查询用户信息,将用户信息展示在列表中 - 将用户信息和表格HTML进行拼接结果响应给客户端
- 当用户访问/add时,呈现表单页面,并实现添加用户信息功能
- 当用户访问/modify时,呈现修改页面,并实现修改用户信息功能
- 当用户访问/delete时,实现用户删除功能
第一步 :写出静态页面
先写出静态页面,直接去找个模板然后写成自己需要的样子就可以。
我练习的时候使用的bootstrap框架,没有下载包而是使用BootCDN 提供的免费 CDN 加速服务(同时支持 http 和 https 协议)。
然后就根据自己的需求找到相应的例子开始使用。
收获:1. 一个术语——布局容器 (知道是左右margin auto,但就是不知道怎么叫哈哈哈)
2.想要一个标签具有多种样式怎么办? 只需将你想要的样式都放到class里空格隔开就行了
放上我写的两个页面:
1. list
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container"> <!--布局容器-->
<h6>
<a href="add.html" class="btn btn-primary">添加用户</a>
</h6>
<table class="table table-bordered table table-hover">
<tr>
<td>用户名</td>
<td>年龄</td>
<td>爱好</td>
<td>邮箱</td>
<td>操作</td>
</tr>
<tr>
<td>小红</td>
<td>20</td>
<td>
<span>化妆</span>
<span>跳舞</span>
<span>烫头</span>
</td>
<td>xiaohong@123.cn</td>
<td>
<a href="" class="btn btn-danger btn-xs">删除</a>
<a href="" class="btn btn-success btn-xs">修改</a>
</td>
</tr>
</table>
</div>
</body>
</html>
2. add
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h3>添加用户</h3>
<form>
<div class="form-group">
<label for="exampleInputEmail1">用户名</label>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="请填写用户名">
</div>
<div class="form-group">
<label for="exampleInputPassword1">密码</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="请输入密码">
</div>
<div class="form-group">
<label for="exampleInputPassword1">年龄</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="请填写年龄">
</div>
<div class="form-group">
<label for="exampleInputPassword1">邮箱</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="请填写邮箱">
</div>
<div class="form-group" >
<label for="exampleInputPassword1">请选择爱好</label>
<div>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox1" value="option1"> 篮球
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox2" value="option2"> 足球
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox3" value="option3"> 羽毛球
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox1" value="option1"> 敲代码
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox2" value="option2"> 跳舞
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox3" value="option3"> 化妆
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox3" value="option3"> 烫头
</label>
</div>
</div>
<button type="submit" class="btn btn-primary">添加用户</button>
</form>
</div>
</body>
</html>
第二步:搭建网站服务器
// 引用系统模块
const http=require('http');
//创建服务器
const app=http.createServer();
//为服务器添加请求事件
app.on('request',(req,res)=>{
res.end('ok');
});
//监听端口
app.listen(3000);
console.log('网站服务器启动成功')
第三步:连接数据库,创建用户集合,向用户集合中插入文档
const mongoose=require('mongoose');
mongoose.connect('mongodb://localhost/playground',{ useNewUrlParser: true })
.then(()=>console.log('数据库连接成功里'))
.catch((err)=>console.log('数据库连接失败'));
const userSchema=new mongoose.Schema({
name:{
type:String,
required:true,
minlength:2,
maxlength:20
},
age:{
type:Number,
min:18,
max:80
}
password:String,
email:String,
hobbies:[String]
});
const User=mongoose.model('User',userSchema);
然后到命令行工具中导入一些数据到数据库
在当前文件夹你 ruquire(‘mongoose’) 能ruquire到吗?
在当前这个user文件夹下确实没有mongoose,但是 require在引入模块的时候是有一定的查找规则的,在当前目录下没有它会向上一级文件夹去寻找
- 32613
第四步:
1. 实现路由功能
先获取到用户的请求方式和请求地址,再对请求方式和请求地址进行判断
const url=require('url');
app.on('request',(req,res)=>{
// 请求方式
const method=req.method;
// 请求地址
const {pathname}=url.parse(req.url);
if(method=='GET'){
}else if(method=='POST'){
}
2. 呈现用户列表页面
GET方式:一般都是数据的请求或页面的传递 (地址栏中地址的请求都属于此方式)
POST方式:一般实现一些功能,e.g. 添加数据或修改数据
因此,呈现用户列表页面要放在GET方式里。
又因为,用户列表页面需要呈现数据库中的数据
所以它不是静态资源,不可以使用静态资源的方式来呈现
那么我们该怎么做呢?
将页面中的所有html标签放入作为一个变量的值,然后再把这个变量的值响应给客户端,然后客户端拿到这个变量的值后会在浏览器中运行这个代码,页面就自然而然的呈现出来了
敲黑板!!!上面这个要能理解这一过程! 就会很简单的。
一定要掌握!
像这样:用户页面也可以呈现出来
if(method=='GET'){
if (pathname=='/list') {
let list=`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container"> <!--布局容器-->
<h6>
<a href="add.html" class="btn btn-primary">添加用户</a>
</h6>
<table class="table table-bordered table table-hover">
<tr>
<td>用户名</td>
<td>年龄</td>
<td>爱好</td>
<td>邮箱</td>
<td>操作</td>
</tr>
<tr>
<td>小红</td>
<td>20</td>
<td>
<span>化妆</span>
<span>跳舞</span>
<span>烫头</span>
</td>
<td>xiaohong@123.cn</td>
<td>
<a href="" class="btn btn-danger btn-xs">删除</a>
<a href="" class="btn btn-success btn-xs">修改</a>
</td>
</tr>
</table>
</div>
</body>
</html>`;
res.end(list);
}
}else if(method=='POST'){
}
3. 让我们将数据库中的数据展示在用户列表页面
因为页面全部内容是在list变量中的,在这个变量里头是无法进行循环操作的
因此,我们要拼接模板字符串。
又因为hobbies是在forEach()中的,因此要再一次将字符串进行拆分(在forEach循环里)
代码如下:
if(method=='GET'){
// 呈现用户列表页面
if (pathname=='/list') {
// 查询用户信息
let users=await User.find();
// console.log(users);
//html字符串
let list=`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container"> <!--布局容器-->
<h6>
<a href="add.html" class="btn btn-primary">添加用户</a>
</h6>
<table class="table table-bordered table table-hover">
<tr>
<td>用户名</td>
<td>年龄</td>
<td>爱好</td>
<td>邮箱</td>
<td>操作</td>
</tr>`;
//对数据进行循环
users.forEach(item=>{
list +=`
<tr>
<td>${item.name}</td>
<td>${item.age}</td>
<td>
`
item.hobbies.forEach(item=>{
list+=`<span>${item}</span>`
})
list+=`</td>
<td>${item.email}</td>
<td>
<a href="" class="btn btn-danger btn-xs">删除</a>
<a href="" class="btn btn-success btn-xs">修改</a>
</td>
</tr>`;
})
list+=`</table>
</div>
</body>
</html>`;
res.end(list);
}
}else if(method=='POST'){
}
- 32614
第五步:当用户访问/add时,呈现表单页面,并实现添加用户信息功能
1. 呈现表单页面(也是使用变量的形式)
else if(pathname=='/add'){
let add=`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h3>添加用户</h3>
<form>
<div class="form-group">
<label for="exampleInputEmail1">用户名</label>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="请填写用户名">
</div>
<div class="form-group">
<label for="exampleInputPassword1">密码</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="请输入密码">
</div>
<div class="form-group">
<label for="exampleInputPassword1">年龄</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="请填写年龄">
</div>
<div class="form-group">
<label for="exampleInputPassword1">邮箱</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="请填写邮箱">
</div>
<div class="form-group" >
<label for="exampleInputPassword1">请选择爱好</label>
<div>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox1" value="option1"> 篮球
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox2" value="option2"> 足球
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox3" value="option3"> 羽毛球
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox1" value="option1"> 敲代码
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox2" value="option2"> 跳舞
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox3" value="option3"> 化妆
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckbox3" value="option3"> 烫头
</label>
</div>
</div>
<button type="submit" class="btn btn-primary">添加用户</button>
</form>
</div>
</body>
</html>`;
res.end(add);}
2. list页面中点击添加用户按钮会跳转到add页面
注意哦!这里是在list变量中需改用户添加按钮的href值。 跑到静态页面修改是没有用的
<h6>
<a href="/add" class="btn btn-primary">添加用户</a>
</h6>
3. 实现添加用户信息功能
- 到add变量中,给form添加method=post,它的请求地址是 /add
- 每个表单项都需要一个name属性,与数据库中的内容对应(如果你没有name属性,服务器端是无法接收到表单中数据的
- 当用户去点击提交按钮的时候,提交到了/add这个路由当中
- 在这个路由当中,我们先去接收post参数,接收完毕后将用户提交的信息添加到数据库中,信息添加完毕后使用writeHead实现页面跳转,跳转到list页面
else if(method=='POST'){
if(pathname=="/add"){
// 声明一个变量接收用户提交的信息
let formDate='';
// 接收post参数
req.on('data',param=>{
formDate+=param;
});
// post参数接收完毕
req.on('end',async ()=>{
let user=querystring.parse(formDate);
// 将用户提交的信息添加到数据库中
await User.create(user);
res.writeHead(301,{
Location:'/list'
});
res.end();
});
}
}
});
第六步:当用户访问/modify时,呈现修改页面,并实现修改用户信息功能
1. 增加页面路由 呈现页面
- 在点击修改按钮的时候 将用户ID传递到当前页面
点击修改按钮时跳转到修改页面
<a href="/modify?id=${item._id}" class="btn btn-success btn-xs">修改</a>
啊,虽然我明白了是通过状态栏传递id到后台,但是还是有点不明白为什么就这样了,哈哈哈 好矛盾啊
可能是还要再去研究一下url这部分的内容。
因为修改页面和添加用户页面差不多,所以直接复制add变量然后修改一些内容就可以了。
2. 从数据库中查询当前用户信息 将用户信息展示到页面中
解析出 ?后的内容(参数),然后在数据库中查找,通过模板字符串拼接显示在修改页面上
// 解构赋值。解析参数返回的是对象
const {pathname,query}=url.parse(req.url,true);
else if (pathname == '/modify') {
let user = await User.findOne({_id: query.id}); //通过返回值的方式接收用户的信息
let hobbies = ['篮球','橄榄球','足球','羽毛球','敲代码','跳舞','化妆','烫头','吃饭', '睡觉', '打豆豆'];
// 呈现修改用户表单页面
let modify = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户列表</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h3>修改用户</h3>
<form method="post" action="/modify?id=${user._id}">
<div class="form-group">
<label>用户名</label>
<input value="${user.name}" name="name" type="text" class="form-control" placeholder="请填写用户名">
</div>
<div class="form-group">
<label>密码</label>
<input value="${user.password}" name="password" type="password" class="form-control" placeholder="请输入密码">
</div>
<div class="form-group">
<label>年龄</label>
<input value="${user.age}" name="age" type="text" class="form-control" placeholder="请填写邮箱">
</div>
<div class="form-group">
<label>邮箱</label>
<input value="${user.email}" name="email" type="email" class="form-control" placeholder="请填写邮箱">
</div>
<div class="form-group">
<label>请选择爱好</label>
<div>`;
hobbies.forEach(item => {
// 判断当前循环项在不在用户的爱好数据组
let isHobby = user.hobbies.includes(item);
if (isHobby) {
modify += `
<label class="checkbox-inline">
<input type="checkbox" value="${item}" name="hobbies" checked> ${item}
</label>
`
}else {
modify += `
<label class="checkbox-inline">
<input type="checkbox" value="${item}" name="hobbies"> ${item}
</label>
`
}
});
modify += `
</div>
</div>
<button type="submit" class="btn btn-primary">修改用户</button>
</form>
</div>
</body>
</html>
`;
res.end(modify);
- 32616
2. 实现修改用户信息功能
点击修改按钮,将修改的数据传到后台(POST方式)
那么后台如何拿到?
使用data事件和end事件,再使用querystring将参数转成对象格式
注意:点击按钮不能获取状态栏的id参数,那么该怎么做呢?
在提交表单的时候,在提交地址上进一步的把id再写一次
因此,在当前表单当中既有GET参数又有POST参数,这是没有问题的
//不是按顺序的代码哦!只是步骤涉及到的,需要自己重组一下呢!!!
// 1. 修改modify变量中的表单-方式、提交地址,
// 此处要注意,模板字符串解析变量要解析哪一个要清楚,此处的id是uesr的(list页面的id是从item获取的)
<form method="post" action="/modify?id=${user._id}">
// 放在POST中
else if(pathname=='/modify'){
// 声明一个变量接收用户提交的信息
let formData='';
req.on('data',param=>{
formData+=param;
});
req.on('end',async()=>{
let user=querystring.parse(formData);
await User.updateOne({_id: query.id}, user);
// 301表示重定向
res.writeHead(301,{
Location:'/list'
});
res.end();
})
}
- 32617
第七步:当用户访问/delete时,实现用户删除功能
思路:
当用户点击删除按钮的时候向服务器端发送一个请求,并且将当前这个用户id作为请求参数传递给服务器端。
那么作为服务器端,需要为当前请求去创建路由,在这个路由当中要接收到客户端传递过来的id参数然后再根据这个id从数据库中把这个用户找到并且删除它。
// 到list变量中去添加href值
<a href="/remove?id=${item._id}" class="btn btn-danger btn-xs">删除</a>
//GET方式中写入此方法
else if(pathname=='/remove'){
await User.findOneAndDelete({_id:query.id});
res.writeHead(301,{
Location:'/list'
});
res.end();
}
- 32618
最后一步:升级代码
所有代码都写到一个文档里不便于修改
将连接数据库和创建集合规则放到单独的文件中,再通过require添加进来
- 32619
跟了一遍下来,有些地方思路还是混乱的,要review哦