本文实例为大家分享了node.js实现简单登录注册的具体代码,供大家参考,具体内容如下
1、首先需要一个sever模块用于引入路由,引入连接数据库的模块,监听服务器
2、要有model层,里面写数据库连接模块和数据库的各种model(表),并导出model对象
3、工具类utils,里面存放一些功能的模块,并且封装后导出 ,例如发送验证码的功能
4、写路由,需要对数据库操作就使用导出的model对象,需要功能模块就使用导出的功能对象
随后返回这个路由,在sever里引入
5、生成api文档
sever模块
//实现登录注册,要先自己写路由放在本地的服务器上
const express=require('express');
//登录注册需要连接到服务器,连接的逻辑单独为一个db包,这里面放着和数据库有关的,比如说数据库的表,数据库的连接
//这里只需要引入连接上述包的连接模块即实现连接
const db=require('./db/connect');
//实例化express模块,这里的实例化对象就是用来操作路由啊使用中间件之类的,都是它
const app=express();
//引入解析请求体的中间件模块,方便路由里可以直接使用数据
const bodyparser=require('body-parser');
//使用这里面的解析请求体的方法
//这里use里面使用的是中间件模块的方法,所以里面是点---------
app.use(bodyparser.urlencoded({extended:false}))
app.use(bodyparser.json())
//下面就是连接路由,先去写下路由,之后在那里导出,这里就可以连接到了
//router里面存放的是全部的不同的路由
//在使用路由之前需要引入能解析请求体的中间件
//引入路由
const userRouter=require('./router/userRouter')
app.use('/user',userRouter);
//开启端口号为3000的本地服务器
app.listen(3000,()=>{
console.log("服务器已开启");
})
数据库model包
1.根目录下的数据库连接
//这个模块不需要导出什么,其他地方引入这个模块就自动执行里面的代码,不需要返回的数据进行下一步操作
//因此不需要导出
const mongoose=require('mongoose');
mongoose.connect('mongodb://localhost/first');//连接到哪一个数据库
let db=mongoose.connection;//数据库连接后的对象,以便于后续对连接过程的监听
db.on("error",console.error.bind(console,"连接异常"));
db.once("open",()=>{
console.log("连接成功");
})
2.model模块(表)
//对数据库操作,需要mongoose模块
const mongoose=require('mongoose');
//由于前面已经连接到数据库了,这里就可以直接创建schema对象了
const userSchema=mongoose.Schema({
us:{type:String,required:true},
ps:{type:String,required:true},
age:Number,
sex:{type:Number,default:0}
})
//这里需要对上面创建的表头(字段)集合转化为模型,即集合为一张表
//并返回一个对象,方便后续对表的操作,这里的对象需要导出,方便在其他模块使用
//这里导出,是为了在路由里使用这个对象对数据库进行操作
const User=mongoose.model("users",userSchema);//使用model方法转化,第一个参数是表名,第二个参数是需要转化的模型
module.exports=User;
工具类utils
//utils是工具类的包,那么发送邮件的程序算是一个工具
//这里将发送的方法封装并导出
const nodemailer=require('nodemailer');
//使用node方法创建发送的对象,接下来发送的方法肯定是该对象操作的
//创建发送对象基本都是固定格式
let transporter=nodemailer.createTransport({
host:"smtp.qq.com",//发送方使用的邮箱
port:465,//端口号,可以在lib/well-known/service.json下找到这些信息
secure:true,
auth:{
user:"1507337624@qq.com",
pass:"" //这里不是邮箱密码,而是邮箱开始第三方发送时给的验证码
}
})
//这里将发送的方法封装,因为只需要导出这个方法,其他并不需要导出
function send(mail,code){
//邮件信息
let mailContent={
from:'<1507337624@qq.com>',
to:mail,
subject:"验证码 ",
text:`您的验证码是$[code],有效期五分钟`
}
//这里的发送是异步的,发送成功与否只有回调函数里才知道,那么总不能发送成功后的代码都写在这个工具里吧
//这只是个工具类,发送成功和失败返回就行,谁用就谁处理
//那么返回回调函数的失败或者成功就要promise对象了,这里直接给发送的结果返回一个promise对象
return new Promise((resolve,reject)=>{
transporter.sendMail(mailContent,(err,data)=>{
//错误优先,err默认为null,另一个参数data包含了发送的一系列信息,状态,数据之类
if(err){
//执行reject就意味着错误,promise就会走catch
reject()
}else{
resolve()
}
})
})
}
module.exports={send}//这里返回的是一个对象,里面有一个属性是send,而不是直接返回send方法本身,其实两者都可以,但是规范上来说更多的是这个
核心路由router
这里写接收并且处理请求的具体方法
//创建一个路由就要先实例化express下创建路由的方法
const express=require('express');
const router=express.Router();//注意这里的router是方法,需要括号
//登录注册等需要对数据库进行操作,这里需要对应的model,先去创建一个model
//创建好了,可以引入了
const User=require("../db/model/userModel");
//注册还需要邮箱验证,那么邮箱验证是一个单独的功能,也就是需要实现的工具类的功能
//所以需要单独一个包存放工具类功能,之后需要的时候引入就可以了,这里先去写
//好了写完了,下面可以导入了
const Mail=require('../utils/mail');
//那么问题来了,导入之后在哪里调用,发送邮箱验证码也是一个请求吧
//既然是请求就应该有对应的接口,因为毕竟是在用户注册上请求发送验证码,所以归在用户路由下
//创建一个全局变量用于保存验证码信息,和注册的邮箱是对应的,因此这个变量是对象,注册的邮箱作为属性
const mailCodes={}
//接下来就可以写路由的接口了
//
//注册接口,生成 接口文档
/**
* @api {post} /user/register 用户注册
* @apiName 用户注册
* @apiGroup User
*
* @apiParam {String} us 用户名
* @apiParam {String} ps 密码
* @apiParam {String} mailCode 验证码
*
* @apiSuccess {String} firstname Firstname of the User.
* @apiSuccess {String} lastname Lastname of the User.
*/
//这里需要对post请求的body分析,需要body-parser中间件,
//但是这里只返回给serve路由 ,因此要在server层引入
router.post('/register',(req,res)=>{
let{us,ps,mailCode}=req.body;
//先判断us和ps还有验证码是否都输入了,如果没输入完成直接就终止执行
if(!us||!ps||!mailCode)return res.send({err:-1,msg:"参数错误"})
//将保存的验证码对应的us属性的值与传来的验证码比较,不对的话直接就终止了,不需要再往下进行了
if(mailCodes[us]!=mailCode)return res.send({err:-4,msg:"验证码不正确"})
//接下来需要判断用户名是否存在,不存在的话就可以注册
User.find({us})
.then((data)=>{
//只要去找了,就会返回数据,没找到返回空,否则返回找到的数据
if (data.length==0){
//没有的话就可以注册了,那么下一步操作也是需要返回promise对象,方便链式调用
//这里涉及到对数据库的操作,需要引入数据库的model,在顶部引入
return User.insertMany({us,ps})
}else{
//如果存在的话就不能注册,那么就需要返回错误信息
return res.send({err:-3,msg:"该用户名已存在"})
}
})
//之前说过对数据库的操作默认返回一个promise对象,可以直接then,catch
//复习一下对数据库操作返回的promise是内部定义的,then里面回调参数是data,即查询或者插入的数据之类
//而catch里面的参数err就是错误信息
.then(()=>{
//这里的res.send是像前台返回的信息,前面路由创建的学习说过了
res.send({err:0,msg:"注册ok"})
})
//无论是几个链式调用,只要有异常都会来到这里
.catch((err)=>{
//这里的错误不是注册过程中重复不能注册的错误,这里应该是数据库连接异常的错误这类
res.send({err:-1,msg:"内部错误"})
})
})
//登录接口,接口文档
/**
* @api {post} /user/login 用户登录
* @apiName 用户登录
* @apiGroup User
*
* @apiParam {String} us 用户名
* @apiParam {String} ps 密码
*
* @apiSuccess {String} firstname Firstname of the User.
* @apiSuccess {String} lastname Lastname of the User.
*/
router.post("/login",(req,res)=>{
let{us,ps}=req.body;
//先判断us和ps还有验证码是否都输入了,如果没输入完成直接就终止执行
if(!us||!ps)return res.send({err:-1,msg:"参数错误"})
//下面的find直接就在数据库里寻找了,找到了返回数据,否则返回空(都是一个数组)
User.find({us,ps})
.then((data)=>{
//如果找到了,则data的长度大于0,反之是没找到
if(data.length>0){
res.send({err:0,msg:"登录 OK"})
}else{
res.send({err:-1,msg:"用户名或密码错误"})
}
})
.catch((err)=>{
res.send({err:-2,msg:"内部错误"})
})
})
//接口文档
/**
* @api {post} /user/getCode 获取验证码
* @apiName 获取验证码
* @apiGroup User
*
* @apiParam {String} us 用户名
*
* @apiSuccess {String} firstname Firstname of the User.
* @apiSuccess {String} lastname Lastname of the User.
*/
//为什么会在这里写一个发送邮箱验证码的接口,它原本是一个方法,
// 但是请求后台发送一个验证码,并且传入需要发送的邮箱,这本身就是一个完整的请求
//想一下,我在页面上注册的时候,输入邮箱后点击发送验证码,这不是一个请求吗,那不就需要一个接口吗
router.post('/getCode',(req,res)=>{
let {us}=req.body;//从请求体中找到需要发送的地址
//这里利用随机函数生成随机数
//强转为整数,这里之所以用变量保存起来,是因为下面需要将验证码和发送的对象一起保存
//发送对象作为属性,验证码为值,因为后续需要比较验证码,所以需要一个全局变量来保存,去上面创建
let code=parseInt(Math.random()*10000)
Mail.send(us,code)
.then(()=>{
//发送成功要返回信息,并且保存验证码
//验证码一定在发送成功后保存,否则随便输入一个不管发送成功还是失败都保存的话会大量占用空间
res.send({err:0,msg:"验证码发送成功"})
mailCodes[us]=code;//将邮箱和验证码一一对应保存起来,方便其他接口的比较
})
.catch(()=>{
res.send({err:-3,msg:"发送失败,请检查邮箱是否正确或网络连接"})
})
})
//路由写完了,现在可以把该数据库返回到操作层了
module.exports=router;