登陆注册
打开cmd执行 mongod --dbpath=d:/data
打开cmd执行 mongo
新建express项目----->在文件路径下打开cmd cnpm i mongoose --save
① 在文件路径下安装 body-parser 的包 cnpm i body-parser --save //用于处理post提交的数据
② 在app.js中引入 body-parser var bodyPaser = require(“body-parser”)
③ 在app.js中添加 app.use(bodyParser.urlencoded({extended:false}));
post取数据的方法
req.body.变量名
get取数据的方法
req.params.变量名
cookie的数据存取(防跳)
①写cookie之前要安装 jsonwebtoken的插件 cnpm i jsonwebtoken --save
②在usercontroller.js 和 index.js 中引入 jsonwebtoken const jwt = require("jsonwebtoken")
写cookie res.cookie("键",值)
读cookie req.cookies.键
sessionStorae的本地存储 关闭浏览器本地存储的数据将会被清空
sessionStorage.setItem("键",值)
sessionStorage.getItem("键")
localStorage的本地存储 只要不删除,值就会存储在浏览器中
localStorage.setItem("键",值)
localStorage.getItem("键")
jsonwebtoken插件 简称JWT,在HTTP通信过程中,进行身份认证(token)。
cnpm i jsonwebtoken --save
const jwt = require(“jsonwebtoken”)
JsonWebToken工作原理
1、客户端通过用户名和密码登录服务器;
2、服务端对客户端身份进行验证;
3、服务端对该用户生成Token,返回给客户端;
4、客户端将Token保存到本地浏览器,一般保存到cookie中;
5、客户端发起请求,需要携带该Token;
6、服务端收到请求后,首先验证Token,之后返回数据。
服务端不需要保存Token,只需要对Token中携带的信息进行验证即可;
无论客户端访问后台的哪台服务器,只要可以通过用户信息的验证即可。
formidable插件用于上传文件 图片等,使用前需要进行插件安装
cnpm i formidable --save
const formidable = require(“formidable”)
crypto模块对密码进行加密
var crypto = require("crypto")
const hash = crypto.createHmac('sha256',req.body.password )//第一个参数是固定算法 第二个参数是用户输入的密码
.update('I love cupcakes')
.digest('hex');
nodejs 官网http://nodejs.cn/api/crypto.html
conn.js
const mongoose = require("mongoose");
mongoose.connect('mongodb://localhost/second',(err)=>{
if(err){
console.log("连接失败")
}else{
console.log("连接成功")
}
})
module.exports = mongoose
usermodel.js
const mongoose = require("../db/conn")
const usermodel = mongoose.model("user",{username:String,password:String},"user")
var finduser=(userinfo,callback)=>{// 查找用户 userinfo 是个键值对 包含里用户名密码
usermodel.find(userinfo).then((data)=>{
callback(data)
})
}
var register=(userinfo,callback)=>{//用户注册
new usermodel(userinfo).save().then(()=>{//添加
callback()
})
}
module.exports={
finduser,
register
}
usercontroller.js
const usermodel = require("../model/usermodel")
const crypto = require("crypto")//引入这个模块对密码进行加密
const jwt=require("jsonwebtoken")
var register=(req,res)=>{
const hash = crypto.createHmac('sha256',req.body.password )//第一个参数是固定算法 第二个参数是用户输入的密码
.update('I love cupcakes')
.digest('hex');
usermodel.finduser({username:req.body.username},(data)=>{//注意post方式取值是req.body.变量名
if(data.length>0){//用户名已经存在 所以点击注册时不能跳转
res.json({
ret:true,
data:false
})
}else{
usermodel.register({username:req.body.username,password:hash},()=>{ //正常注册
res.json({
ret:true,
data:true
})
})
}
})
}
var isregister=(req,res)=>{//判断是否已经注册
usermodel.finduser({username:req.body.username},(data)=>{//在数据库中查找用户输入的用户名
if(data.length>0){//告诉用户 所输入的用户名是否存在
/*res.cookie('abc',"def")//服务器端向客户端写cookie*/
res.json({
ret:true,
data:false//存在就返回一个false
})
}else{
res.json({
ret:true,
data:true//不存在将继续注册
})
}
})
}
var login=(req,res)=>{//登陆
let{username,password}=req.body;//解构赋值
const hash = crypto.createHmac('sha256',password )//第一个参数是固定算法 第二个参数是用户输入的密码
.update('I love cupcakes')
.digest('hex');
usermodel.finduser({username,password:hash},(data)=>{
if(data.length>0){//如果数据库中匹配到对应的用户名 和密码
var token = jwt.sign({username,time:new Date().getTime()},"haha",{expiresIn:50})//获取用户名 和当前的时间 然后写一个加密字符串 最后设定一个过期时间 防跳
res.cookie('token',token)//cookie写数据
res.json({
ret:true,
data:true
})
}else{
res.json({
ret:true,
data:false
})
}
})
}
var quit=(req,res)=>{//退出功能
if(req.cookies.token){//如果存在token
res.cookie("token","")//清空token
res.json({
data:{
logout:true
}
})
}
}
module.exports={
register,
login,
isregister,
quit
}
users.js
var express = require('express');
var router = express.Router();
const usercontroller = require("../controller/usercontroller")
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.post("/register",usercontroller.register)
router.post("/login",usercontroller.login)
router.post("/isregister",usercontroller.isregister)
module.exports=router
register.html
<body>
<input type="text" name="username" id="username" value="" />
<input type="text" name="password" id="password" value="" />
<button id="reg">注册</button>
<div id="info"></div>
</body>
</html>
<script type="text/javascript">
$("#reg").click(function(){//提交注册请求
$.post("/users/register",{//用post向数据库传值 这里前面加/users是因为app.js
中的中间件app.use('/users', usersRouter); 规定的写法
username:$('#username').val(),
password:$("#password").val()
}).then((res)=>{//数据库返回一个res 如果data为true则可以注册
if(res.data){
location.href="login.html"
}else{
$("#info").html("注册失败")
}
})
})
$("#username").keyup(function(e){//验证用户名是否存在
if($(this).val()==="")return;
$.post("/users/isregister",{//在输入的过程中判断用户名是否存在
username:$("#username").val()
}).then((res)=>{
if(res.data){
$("#info2").html("√")
}else{
$("#info2").html("用户名已存在")
}
})
})
</script>
login.html 登录后在list页面显示用户名---sessionStorage
<body>
<input type="text" name="username" id="username" value="" />
<input type="text" name="password" id="password" value="" />
<button id='login'>登陆</button><p>如果你没有用户名请<a href="register.html">注册</a></p>
<div id="info">
</div>
</body>
</html>
<script type="text/javascript">
$("#login").click(function(){//登录 验证
$.post('/users/login',{//向数据库传递用户名和密码
username:$("#username").val(),
password:$("#password").val()
}).then((res)=>{
if(res.ret){//如果匹配上了 则跳转到list页面
sessionStorage.setItem("username",$("#username").val())//sessionstorage是本地存储 窗口关闭后本地存储自动清空 setItem()是建立存储内容 存的是用户名(“键”,值) 用于在list等页面显示登录之后的用户名
location.href="list.html"
}else{
$("#info").html('登录失败')
}
})
})
</script>
smodel.js
const mongoose = require("../db/conn")
const smodel = mongoose.model("second",{name:String},"second")
var getData=(callback)=>{//获取数据 从数据库里拿到所有的数据 回调函数里要有 data 如果有data那么controller中的res接收的时候就需要甩数据
smodel.find().then((data)=>{
callback(data)
})
}
var addData=(name,callback)=>{//添加数据 向数据库中传值 回调函数中没有data
new smodel({name:name}).save().then(()=>{
callback()
})
}
var delData=(id,callback)=>{//删除数据 在数据库中搜索对应的id 并删除 回调函数中没有data
smodel.remove({_id:id}).then(()=>{
callback()
})
}
var findData=(id,callback)=>{//查找数据 在数据库中查找id对应的数据 回调函数中有data
smodel.find({_id:id}).then((data)=>{
callback(data)
})
}
var modifyData=(id,username,callback)=>{//修改数据 在数据库中修改对应数据 回调函数里没有data
smodel.update({_id:id},{$set:{name:username}}).then(()=>{
callback()
})
}
var queryData=(kw,callback)=>{//模糊查找 在数据库中找到符合要求的数据返给前端 回调函数里有data
smodel.find({name:new RegExp(kw)}).then((data)=>{
callback(data)
})
}
var pageData=(page,pageSize,callback)=>{//分页 在数据库中将数据分页传递给前端 回调函数中有data
smodel.find().skip((page-1)*pageSize).limit(Number(pageSize)).then((data)=>{
callback(data)
})
}
module.exports={
getData,
addData,
delData,
findData,
modifyData,
queryData,
pageData
}
scontroller.js
formidable插件用于上传文件 图片等,使用前需要进行插件安装 cnpm i formidable --save
const smodel = require("../model/smodel")
var formidable = require('formidable')//引入上传模块
const fs = require("fs")
var getList=(req,res)=>{
smodel.getData((data)=>{
res.json({
list:data
})
})
}
var addList=(req,res)=>{
smodel.addData(req.params.name,()=>{
res.json({
ret:true,
data:true
})
})
}
var delList=(req,res)=>{
smodel.delData(req.params.id,()=>{
res.json({
ret:true,
data:true
})
})
}
var findList = (req,res)=>{
smodel.findData(req.params.id,(data)=>{
res.json(data)
})
}
var modifyList=(req,res)=>{
smodel.modifyData(req.params.id,req.params.username,()=>{
res.json({
ret:true,
data:true
})
})
}
var queryList=(req,res)=>{
smodel.queryData(req.params.kw,(data)=>{
res.json(data)
})
}
var pageList=(req,res)=>{
smodel.getData((da)=>{
smodel.pageData(req.params.page,req.params.pageSize,(data)=>{
res.json({
list:data,
count:Math.ceil(da.length/req.params.pageSize)
})
})
})
}
var upload=(req,res)=>{//上传
var form = new formidable.IncomingForm();
form.uploadDir = './public/upload'
form.parse(req, function(err, fields, files) {//第一个参数是错误返回 第二个是文档的所有字段 第三参数是上传的文件信息
if(!files.wj)return//如果没有传文件就返回
fs.rename(files.wj.path,'./public/upload/'+files.wj.name,()=>{//存储文件的文件夹路径
console.log('上传成功')
})
res.json({
path:'/upload/'+files.wj.name//返回文件存储的路径
})
});
}
module.exports={
getList,
addList,
delList,
findList,
modifyList,
queryList,
pageList,
upload
}
index.js
var express = require('express');
var router = express.Router();
const scontroller=require("../controller/scontroller")
const jwt = require("jsonwebtoken")
router.get('/', function(req, res, next) {
res.redirect('/login.html'); //有‘/’的时候跳转到登陆页面
});
router.use(function(req,res,next){//这是一个中间件 防跳
if(req.url!=='/users/login'&&req.url!=='/users/register' &&req.url!=='/users/isregister'){ // 登陆,注册,验证用户名是否存在这三个请求是不用token令牌验证的, 之后的增删改查都需要经过令牌验证才可以进行操作或者页面跳转
jwt.verify(req.cookies.token,'haha',(err)=>{//jwt.verify()是一个验证 方法 用于验证token, 第二个参数要与usercontroller中的login方法中的加密字符串一致 第三个参数是回调函数
if(!err){//验证通过
next()
}else{ //验证token失败
res.json({
msg:"read token fail"
})
}
})
}else{
next();//如果是登陆 注册 和验证用户名这三个操作 则可以直接进行下一步操作(页面跳转),不需要token验证
}
})
router.get("/list",scontroller.getList)
router.get("/add/:name",scontroller.addList)
router.get("/del/:id",scontroller.delList)
router.get("/find/:id",scontroller.findList)
router.get("/modifyok/:id/:username",scontroller.modifyList)
router.get("/query/:kw",scontroller.queryList)
router.get("/page/:page/:pageSize",scontroller.pageList)
router.post("/upload",scontroller.upload)
module.exports = router;
list.html
<head>
<meta charset="UTF-8">
<title></title>
<script src="/javascripts/jquery.js"></script>
<script src="/javascripts/baiduTemplate.js"></script>
<script src="/javascripts/nav.js"></script>
</head>
<body>
<div id="nav"></div>
<div id="box"></div>
<script type="text/html" id="tem">
<input type="text" name="txt" id="txt" value="" />
<button id="add">添加</button>
<ul>
<% for(var i=0; i< list.length;i++){%>
<li>
<%=list[i].name%>
<button class="del" data-id="<%=list[i]._id%>">删除</button>
<button class="btn" data-id="<%=list[i]._id%>">修改</button>//mongoose数据库中的id变量名为_id
</li>
<% } %>
</ul>
<%for(var p=1 ; p<=count ; p++){%>
<span class="page" data-page="<%=p%>" ><%=p%></span>
<% } %>
</script>
</body>
</html>
<script type="text/javascript">
function pageData(page,pageSize){//分页
$.get("http://localhost:3000/page/"+page+"/"+pageSize).then((res)=>{//这里的page,pagesize是function传过来的形参 从服务端取值
if(res.msg){//如果token读取失败 就跳回登录页面
location.href="login.html"
}else{//如果读取成功就显示正常的list页面
nav($("#nav"))
var content=baidu.template("tem",{
list:res.list,
count:res.count//count是总页数 page是当前页数 pagesize是每一页的信息数
})
$("#box").html(content)
}
})
}pageData(1,2)
$(document).on('click','.page',function(){//点每一页显示不同的内容
pageData($(this).attr("data-page"),2)
})
$("#box").on('click','#add',function(){//添加
$.get("http://localhost:3000/add/"+$("#txt").val()).then((res)=>{//向服务端传值
if(res.ret){
location.reload()
}
})
})
$("#box").on('click','.del',function(){//删除
if(!confirm("确定要删除吗"))return
$.get("http://localhost:3000/del/"+$(this).attr("data-id")).then((res)=>{
if(res.ret){
location.reload()
}
})
})
$(document).on('click','.btn',function(){//修改
$.get("http://localhost:3000/find/"+$(this).attr("data-id")).then((res)=>{
location.href="modify.html?id="+$(this).attr("data-id")
})
})
</script>
modify.html 修改
<script src="/javascripts/jquery.js"></script>
<script src="/javascripts/baiduTemplate.js"></script>
</head>
<body>
<input type="text" name="txt" id="username" value="" />
<input type="text" name="" id="id" value="" />
<button id="modifyok">确认修改</button>
</body>
</html>
<script type="text/javascript">
var id=location.search.substring(1).split("=")[1]//问号传参 取值
console.log(id)
$.get("http://localhost:3000/find/"+id).then((res)=>{
$("#username").val(res[0].name)//传回来的res是一个数组,所以用数组的方法取值
$("#id").val(res[0]._id)
})
$("#modifyok").click(function(){
$.get("http://localhost:3000/modifyok/"+$("#id").val()+"/"+$("#username").val()).then((res)=>{
if(res.ret){
location.href="/list.html"
}
})
})
</script>
query.js 模糊查找
<script src="/javascripts/baiduTemplate.js"></script>
<script src="/javascripts/jquery.js"></script>
<script src="/javascripts/nav.js"></script>
</head>
<body>
<div id="nav">
</div>
<input type="text" name="txt" id="kw" value="" />
<button id="btn">查找</button>
<div id="box">
</div>
<script type="text/html" id="tem">
<%for(var i = 0 ; i < list.length ; i++){%>
<li><%=list[i].name%></li>
<% } %>
</script>
</body>
</html>
<script type="text/javascript">
nav($("#nav"))
$("#btn").click(function(){
alert(1)
$.get("http://localhost:3000/query/"+$("#kw").val()).then((res)=>{//通过关键字模糊查找
var content=baidu.template("tem",{
list:res
})
$("#box").html(content)
})
})
upload.js 上传文件
<script src="/javascripts/jquery.js"></script>
<script src="/javascripts/baiduTemplate.js"></script>
<script src="/javascripts/nav.js"></script>
</head>
<body>
<!--<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="wj" id="wj" value="" />
<input type="submit" value="提交"/>
</form>--> //表单提交的方法
<div id="nav">
</div>
<div id="box">
<input type="file" name="myfile" id="myfile" value="" />
<button id="btn">上传</button>
</div>
<script type="text/javascript">
nav($("#nav"))
$("#btn").click(function(){
var form = new FormData;
form.append('wj',myfile.files[0])
console.log(form)
$.ajax({
type:"POST",
url:"/upload",
async:true,
cache:false,//不适用缓存
processData:false,//传输的数据不被jq封装
contentType:false,//文件编码不采用jq的形式
data:form
}).then((res)=>{
var img = new Image;
img.src = res.path;
document.body.append(img)//只传图片 如果不写可以传各种文件
})
})
</script>
</body>
</html>
nav.js
var nav=(node)=>{
var navcontent=$(`<div>
<a href="list.html">显示列表</a>||
<a href="query.html">查询</a>
</div>`)
var temSpan = $("<span>").html("你好:"+sessionStorage.getItem("username"))//getItem是取值
temSpan.css("width","80px")
navcontent.append(temSpan)//将取到的值填入进去
var btn= $('<button>退出</button>')
btn.click(function(){
$.post("/users/quit").then((res)=>{
if(res.data.logout){
alert("谢谢使用")
location.href='login.html'
}
})
})
/*var content=baidu.template(navcontent)*/
navcontent.append(btn)
node.html(navcontent)
}