//用户信息增删改查
//1.搭建网站服务器,实现客户端与服务器端的通信 ===>已完成
var http = require('http')
var app = http.createServer()
var mongoose = require('mongoose')
var url = require('url')
var querystring = require('querystring');
/* const { isSymbol } = require('util'); */
//2.连接数据库,创建用户集合,向集合中导入文档 ===>已完成
require('./model/index.js')
//接收用户集合
var zsgc = require('./model/user.js')
//仍有效
//已经创建完数据库集合
//将user.json导入到zsgc集合中
app.on('request',async(req,res)=>{
//3.当用户访问/list时,将所有用户信息查询出来 ==>通过路由实现,而且是在地址栏中输入get请求实现,即为get请求中的list路由 ===>已完成
//实现路由功能
//呈现用户列表页面
//从数据库中查询用户信息,并将信息展示到列表页面中
if(req.method=='GET'){
//获取其路由pathname,对象解构得到其内部属性
var {pathname,query} = url.parse(req.url,true)
//实现路由
if(pathname=='/list') {
//从数据库中查询用户信息,并将信息展示到列表页面中
var realfile = await zsgc.find()
//将要分离结果与执行过程的方法前加 await,最外层的回调函数前要加async,现在我只要结果,用异步
//现在能够得到数据库中的值,通过异步函数的方式,在前方加await将结果与执行过程分离,将其结果,查询到的包含所有文档的find对象传递给realfile变量
/* console.log(realfile) */
//实现将数据库中传入的realfile包含文档的对象信息展示到列表页面中==>即将list变量中静态的部分html代码变成动态的,即将需要部分进行代码拼接
//当用户访问list路由时发送请求,呈现用户列表页面(将html标签作为一个变量,用反引号引起来,再把这个变量响应给服务器)
//4.将用户信息和表格HTML进行拼接并将拼接结果响应回客户端===>已完成
var list = `<!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">
<h6>
<a href="/add" class="btn btn-primary">添加用户</a>
</h6>
<table class="table table-striped table-bordered">
<tr>
<td>用户名</td>
<td>年龄</td>
<td>爱好</td>
<td>邮箱</td>
<td>操作</td>
</tr>`
//明确目的,这里需要从数据库导入的值正是下方这一整块tr,由于有多条文档,每条都要展示,因此用到循环foreach,realfile得到的是find数组[{},{}]
realfile.forEach(item=>{
//同理,td爱好部分同样需要循环,需要哪块就拿哪块,把两边放到 += 包裹,再重新写 ` ` 分隔即可!
//而这里不要写realfile.hobbies.forEach,在其循环内部对应模块此时应为动态的item即为对象,应该是item.hobbies.forEach!
//注意方法名字为forEach,不是foreach,否则报错 UnhandledPromiseRejectionWarning: TypeError: realfile.foreach is not a function
//我要加的仅仅是span部分,时刻注意其对应上级要放到上下部分,即td,要循环的仅仅是hobbies中的多个span,因此写一个模板即可!
//拼接字符串中换上动态的值外部用${}包裹即可
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="/modify?id=${item._id}" class="btn btn-success btn-xs">修改</a>
/* <a href="/remove2?id=${item._id}" class="btn btn-danger btn-xs">删除</a> */
<a href="/remove?id=${item._id}" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>`
})
list +=` </table>
</div>
</body>
</html>
`;
res.end(list)
//输入http://localhost:8080/list即可显示数据库调用值动态显示后的页面,达到效果,因为没有设置别的路由,因此别的路径均加载不出来页面
}
//5.当用户访问/add时,呈现表单页面,并实现添加用户信息功能==>仍为get请求
//单击列表页的添加用户按钮,跳转到add页面=> <a href="/add" class="btn btn-primary">添加用户</a>
//添加用户信息功能 =>向服务器提交数据时表单必须要用post请求,设置form的method,而且向服务器提交的每个input信息必须有name属性
//一定注意 提交表单是post请求,因此单击提交按钮实现添加用户信息功能需要在post请求中设置单独的路由
// get请求下的add路由仅仅是展示,实现功能交给post中的add路由,通过get请求中from的 action属性就可实现,单击完提交按钮即可跳转到post请求中的add路由并对表单进行处理
if(pathname=='/add'){
var add=`<!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="/add">
<div class="form-group">
<label>用户名</label>
<input name="name" type="text" class="form-control" placeholder="请填写用户名">
</div>
<div class="form-group">
<label>密码</label>
<input name="password" type="password" class="form-control" placeholder="请输入密码">
</div>
<div class="form-group">
<label>年龄</label>
<input name="age" type="text" class="form-control" placeholder="请填写邮箱">
</div>
<div class="form-group">
<label>邮箱</label>
<input name="email" type="email" class="form-control" placeholder="请填写邮箱">
</div>
<div class="form-group">
<label>请选择爱好</label>
<div>
<label class="checkbox-inline">
<input name='hobbies' type="checkbox" value="足球"> 足球
</label>
<label class="checkbox-inline">
<input name='hobbies' type="checkbox" value="篮球"> 篮球
</label>
<label class="checkbox-inline">
<input name='hobbies' type="checkbox" value="橄榄球"> 橄榄球
</label>
<label class="checkbox-inline">
<input name='hobbies' type="checkbox" value="敲代码"> 敲代码
</label>
<label class="checkbox-inline">
<input name='hobbies' type="checkbox" value="抽烟"> 抽烟
</label>
<label class="checkb-ox-inline">
<input name='hobbies' type="checkbox" value="喝酒"> 喝酒
</label>
<label class="checkbox-inline">
<input name='hobbies' type="checkbox" value="烫头"> 烫头
</label>
</div>
</div>
<button type="submit" class="btn btn-primary">添加用户</button>
</form>
</div>
</body>
</html>`
//实现代码拼接并通过响应动态呈现到页面中去
res.end(add)
}
else if(pathname == '/modify'){
//6.当用户访问/modify时,呈现修改页面,并实现修改用户信息功能
//list列表页单击修改按钮跳转到mofidy路由==>==> list 中 <a href="/modify" class="btn btn-success btn-xs">修改</a>
//get请求路由实现呈现功能
//在此需要将表单的值传到post请求中的modify路由进行处理,因此需要找到当前修改项在数据库中的位置,并将输入的值动态传给post modify路由
//如何获得修改项在数据库中的位置,仍然借助上方a标签内id属性,<a href="/modify?id=${item._id}" class="btn btn-success btn-xs">修改</a>
//这里a标签内的item即为数据库中循环的每个文档,因此item._id就能得到其对应唯一标识,而且是每一个item都有"修改",因此通过query.id能找到每个对应文档且每次对应只能找到一个文档
var user1 = await zsgc.findOne({_id:query.id})
/* console.log(user1) */
//var {pathname,query} = url.parse(req.url,true)
//注意,加多个参数时,一定要在对象解构后面加true,否则传不过来值,这里的query.id中的id没有值,导致下方一连串报错
// 这里报错,因为对象解构没用{query},重新写好即可
/* console.log(user1) *///至此已经得到点击修改按钮对应数据库中的文档了
//将其修改的值从动态传入form,这里的值跟集合规则创建的一个模板,因此不用担心名字,动态传入--> input中多加value属性,value='${user1.xxx}'
var hobbiesall = ['足球', '篮球', '橄榄球', '敲代码', '抽烟', '喝酒', '烫头', '吃饭', '睡觉', '打豆豆']
//这里多了没事,经过判断不会创建lable,只有有的才会创建
var 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=${user1._id}">
<div class="form-group">
<label>用户名</label>
<input type="text" name='name' value='${user1.name}' class="form-control" placeholder="请填写用户名">
</div>
<div class="form-group">
<label>密码</label>
<input type="password" value='${user1.password}' name='password' class="form-control" placeholder="请输入密码">
</div>
<div class="form-group">
<label>年龄</label>
<input type="text" name='age' value='${user1.age}' class="form-control" placeholder="请填写邮箱">
</div>
<div class="form-group">
<label>邮箱</label>
<input type="email" name='email' value='${user1.email}' class="form-control" placeholder="请填写邮箱">
</div>
<div class="form-group">
<label>请选择爱好</label>
<div>`
/* console.log(user1.hobbies) */
hobbiesall.forEach(item=>{
//hobbiesall.includes(item)方法会返回一个布尔值,如果有即true,没有即flase
//当前获取到的文档中的爱好是否在hobbiesall数组中出现,若存在,即返回选中的,没选中返回没选中的lable==>同时也能实现修改功能,记住吧!
//只能这么写,否则不对!,而且注意一点,至此已经显示出所有爱好(包括选中与未选中),并且此刻修改的value值可以动态送给服务器端
//${item}能够遍历到每个爱好,不管存不存在,其值就是当前循环项,否则每个就相同都是静态的了!
var realp = user1.hobbies.includes(item)
if(realp){
modify +=`
<label class="checkbox-inline">
<input name='hobbies'type="checkbox" value="${item}" checked> ${item}
</label>
`}
else {
modify +=`
<label class="checkbox-inline">
<input name='hobbies'type="checkbox" value="${item}"> ${item}
</label>
`}
//这些代码可以实现上来就显示之前选的爱好值并呈现选中或未选中状态。
})
modify+=`</div>
</div>
<button type="submit" class="btn btn-primary">修改用户</button>
</form>
</div>
</body>
</html>`
res.end(modify)
//这里要循环的是整个label标签,并非只要循环内部input,是一个整个label套一个input,如此循环,效果也是如此
//由于复选框的选定状态不确定,因此要用if来判断,不能写静态的选中了就创建checked属性的lablel,反之不加
//至此已经该数据全部变成动态,现在交由post请求中的modify路由处理
}
//7.当用户访问/delete时,实现用户删除功能
else if(pathname == '/remove'){
//这里不涉及到表单,因此不需要单独设置post 路由进行修改,这里直接在get请求的remove路由将功能实现即可
//首先拿到其对应点击删除文档的id,以便找到文档
//首先单击删除按钮跳转到删除路由(即为此处)进行处理 ==> <a href="/remove" class="btn btn-danger btn-xs">删除</a>
//如果不在上方的a连接内传递id,会发生什么情况呢,此时的query应该为undefined,因为query是由对象解构来的,对象只有pathname
/* console.log(query.id) */ //此刻返回undefined,因此要在a链接传递id,这里不是post和get的区别,是不传解构而来的对象就没有query,也验证了
//<a href="/remove?id=${item._id}" class="btn btn-danger btn-xs">删除</a>
console.log(query.name)//成功返回了id
console.log(query.id)//成功返回了id
//根据id找到数据库内的数据进行删除操作,由于传来的query.id值为 item._id,因此直接拿query.id作为_id的条件即可找到对应的那条文档
var id=query.id;
await zsgc.findOneAndDelete({_id:query.id})
//重定向回列表页
res.writeHead(301,{
location:'/list'
})
/* location.href("http://localhost:8080/add") */
res.end()
}
else if(pathname == '/remove2'){
//这里不涉及到表单,因此不需要单独设置post 路由进行修改,这里直接在get请求的remove路由将功能实现即可
//首先拿到其对应点击删除文档的id,以便找到文档
//首先单击删除按钮跳转到删除路由(即为此处)进行处理 ==> <a href="/remove" class="btn btn-danger btn-xs">删除</a>
//如果不在上方的a连接内传递id,会发生什么情况呢,此时的query应该为undefined,因为query是由对象解构来的,对象只有pathname
/* console.log(query.id) */ //此刻返回undefined,因此要在a链接传递id,这里不是post和get的区别,是不传解构而来的对象就没有query,也验证了
//<a href="/remove?id=${item._id}" class="btn btn-danger btn-xs">删除</a>
console.log(query.id)//成功返回了id
//根据id找到数据库内的数据进行删除操作,由于传来的query.id值为 item._id,因此直接拿query.id作为_id的条件即可找到对应的那条文档
await zsgc.findOneAndDelete({_id:query.id})
//重定向回列表页
res.writeHead(301,{
location:'/list'
})
/* location.href("http://localhost:8080/add") */
res.end()
}
}
else if(req.method=="POST"){
//因为要单独设置post请求中的add路由,因此必须获得pathname属性,在post请求中该如何获取呢?
var {pathname} = url.parse(req.url)
//post接受请求参数,期间拼接字符,最后输出字符,要对其post请求from进行处理,首先待拿到数据
if(pathname=='/add'){
// 接受用户提交的信息
let formData = '';
// 接受post参数
req.on('data', param => {
formData += param;
})
req.on('end',/* async */()=>{
//至此,应该实现了在get请求下add路由中 from内书写,点击提交按钮,并转到post请求下add路由中对接收的form数据进行拼接处理
//因此,只要在get请求下的add路由下的from表单输入值,action跳转都能接收到值并进行拼接,实验一下
/* console.log(querystring.parse(formData)) */
/* { name: 'qqweqwe',
password: 'asdasdasd',
age: '1314',
email: '26021231231237@qq.com',
hobbies: [ '足球', '橄榄球' ] } 已成功获取对象,这里一定注意的是post请求pathname路由的获得一定要重新看一遍!*/
//5.在post请求中接收完form参数,开始实现添加用户信息功能==>实现,这段添加用户信息功能必须放到 req.end中,否则失效!
var USER = querystring.parse(formData)
zsgc.create(USER,(err,result)=>{
console.log(err)
console.log(result)
})
//这两种方法均可实现,就算采用了异步函数,也没有达到执行过程和拿取结果分离的目的,因此都行
//USER 为对象,包括一堆属性,即为按照模板form输入的值拿出来了,将这个对象添加到zsgc数据库里,符合集合规则
/* await zsgc.create(USER); */
//路由已实现添加功能,现在将其转回列表页
//301代表重定向 location代表跳转地址,重定向后面一定要加res.end(),不加跳转不了!
res.writeHead(301,{
location:'/list'
});
//重定向功能实现
res.end()
})
}
else if (pathname == '/modify'){
//首先接收form传来的这一行动态修改完成的文档
var paramdata2 =''
req.on('data',param=>{
paramdata2+=param
})
req.on('end',async()=>{
var {pathname,query} = url.parse(req.url,true)
//这里query失效,没有值,重新调用一遍获得即可解决问题
//将其转换为对象输出,借助模块方法querystring.parse()
/* console.log(querystring.parse(paramdata2)) */
//至此,应该实现在get请求modify路由中输入文档,动态传入form,再到post modify路由处理,最后显示输入的文档,测试一下
console.log(query)//query为undefined,因此id报错id
var updatauser = querystring.parse(paramdata2)
await zsgc.updateOne({_id: query.id}, updatauser)
res.writeHead(301, {
Location: '/list'
});
res.end();
})
}
}})
app.listen(8080);
console.log("服务器启动成功")
nodejs+mongodb 实现增删改查(字符串拼接 初期)
最新推荐文章于 2023-04-26 07:30:00 发布