express框架和mongodb的联合使用的聊天小程序
事先声明: 这是本人根据express框架的学习,以及mongodb的使用做出来的一个十分简易的聊天小程序。
*实现功能:用户注册、登录、多个窗口用户实时聊天、可以发送图片进入聊天界面
缺点:本软件只是本人针对所学来进行功能实现,因此页面十分简洁,除了部分页面以外,没有使用css进行样式控制,mongodb服务只能在本机上使用,同局域网的其他用户无法访问到mongodb数据库,因此在其他的同局域网的电脑不能进行注册和登录功能
项目的目录结构
创建express 项目
express --view=ejs weChat // 创建一个项目名为WeChat的项目
cnpm i // 根据package.json的依赖内容,安装环境依赖
cd weChat // 进入WeChat目录
npm start // 打开服务 打开浏览器访问localhost:3000 没有报错代表框架搭建成功
mongodb 服务器和客户端
mongod --dbpath d:\db // 打开mongodb服务 出现端口号为27017 代表服务开启成功
mongo // 打开mongodb客户端,连接到mongodb服务,进行数据库操作
连接mongodb服务器
首先我们需要在WeChat项目下安装mongoose环境依赖
cnpm i mongoose --save
在wechat目录下建立一个新的文件夹 db 在db下新建一个js文件 connect.js,具体代码如下
const mongoose = require("mongoose") // 引入mongoose模块
// 连接到本地mongo数据库 端口号为27017 数据库为testDb 然后对connect函数的返回值进行错误处理,如果没有出错就打印连接成功,如果出错就打印连接失败
mongoose.connect('mongodb://localhost:27017/testDb', {useNewUrlParser: true},(err) => {
if(!err){
console.log("数据库连接成功")
}else{
console.log("数据库连接失败")
}
});
connect.js 内容完成后 需要在routers下的index.js下面引用connect.js
var conn = require("../db/connect")
页面搭建
我只搭建了三个页面,登录,注册和聊天页面 (login.html,register.html,client.html)
记得都要引入jQuery js文件,js文件可以自己下载或者直接在www.npmJS.com官网上搜索,直接引入
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<--登录-->
<input type="text" id="username">
<input type="password" name="password" id="password">
<input type="button" value="提交" id="submit">
<--注册-->
<input type="text" id="username">
<input type="password" name="password" id="password">
<input type="button" value="提交" id="submit">
<--客户端-->
<div id="box"></div>
<input type="text" id="text">
<input type="button" value="发送" id="submit"><br />
<input type="file" name="file" id="myFile">
<input type="button" value="上传" id="upload">
配置登录注册路由
本部分属于users.js里面的接口,因此访问时需要使用/users/+接口,因此以下代码都是写在routes目录下的users.js中
在进行登录注册的时候我们需要使用以下几种模块
mongoose 模块 主要用于与mongo数据库进行链接
crypto 模块 主要作用是对密码进行加密
var login = require("mongoose")
var crypto = require("crypto")
引入模块完成后,我们对于mongoose模块需要定义一个模型
// 定义一个mongoose模型 集合的名字是 log 集合的数据格式是{username:String,password:String}
const Info = login.model("log",{username:String,password:String},"log")
注册接口
- 定义访问接口为 /register 前段进行访问的接口为 /users/register
- 获取前端传过来的注册信息(用户名和密码)get的接收方式为req.query,post的接收方式为req.body
- 对获取到的密码进行加密,加密需要使用crypto模块
- 对获取到的用户名与mongo数据库中log集合中的信息进行对比,是否有相同的用户名
- 如果有相同的用户名,返回失败信息,如果成功,返回成功信息
router.post("/register", function (req, res, next) {
// let file = path.resolve(__dirname,"../public/json/loginData.json")
// console.log(file)
let name = req.body.username
let pwd = req.body.password
// 对密码进行加密,加密的方法为sha256,update里面的信息可以随便填,输出的信息为hex格式(即十六进制)
const hash = crypto.createHmac('sha256', pwd)
.update('hash')
.digest('hex');
// 寻找是否具有相同的用户名
Info.find({username:name}).then(response => {
if(response.length > 0){
res.json({
status : 0,
message:"用户名已被占用"
})
}else{
Info({username:name,password:hash}).save().then(() => {
res.json({
status : 0,
message:"用户注册成功,点击确定跳转登录界面"
})
})
}
})
})
注册界面js代码
给提交按钮绑定点击事件,获取用户名和密码,然后传递给后台,根据后台返回的数据判断用户是否注册成功
$("#submit").on("click",function() {
var username = $("#username").val()
var password = $("#password").val()
$.post("/users/register",{username,password}).then(res => {
if(res.status === 0){
alert(res.message)
location.href='./login.html'
}else{
alert(res.message)
}
})
})
登录接口
- 定义访问接口为 /login 前段进行访问的接口为 /users/login
- 获取前端传过来的登录信息(用户名和密码)get的接收方式为req.query,post的接收方式为req.body
- 对获取到的密码进行加密,加密需要使用crypto模块
- 对获取到的用户名与mongo数据库中log集合中的信息进行对比,用户名和密码是否相同,如果相同,返回成功信息,如果成功,返回失败信息
router.post("/login", function (req, res, next) {
// let file = path.resolve(__dirname,"../public/json/loginData.json")
// console.log(file)
let name = req.body.username
let pwd = req.body.password
// 这个加密中的update里面信息和注册时写入的信息一样
const hash = crypto.createHmac('sha256', pwd)
.update('hash')
.digest('hex');
Info.find({username:name,password:hash}).then((response) => {
if(response.length > 0){
req.session.user = name
res.json({
status : 0,
message:"用户登录成功,点击确定跳转登录界面",
name:req.session.user
})
}else{
res.json({
status : -1,
message:"登录失败,密码或者用户名错误"
})
}
})
})
登录界面js代码
给提交按钮绑定点击事件,获取用户名和密码,然后传递给后台,根据后台返回的数据判断用户是否登录成功
$("#submit").on("click",function() {
var username = $("#username").val()
var password = $("#password").val()
$.post("/users/login",{username,password}).then(res => {
console.log(res)
if(res.status === 0){
alert(res.message)
location.href = "./client.html?name=" + res.name
}else{
alert(res.message)
}
})
})
socket.io 通讯技术
接下来就是最重要的相互通讯技术的实现,需要socket.io 插件来实现,首先通过cnpm安装socket.io插件
cnpm i socket.io --save
然后在bin目录下的www文件的 var server = http.createServer(app);这句后面写以下代码
var io = require("socket.io")(server)
io.on('connection', (socket) => {
socket.on("msg",(data) => {
// 判断是否是用户,如果不是用户则将输入的信息存储为用户名
if(!socket.user){
socket.user = data
io.emit("msg","欢迎"+data +"进入聊天室")
}else{
io.emit("msg",socket.user+"说:"+data)
}
})
socket.on("disconnect",(data) => {
socket.broadcast.emit("msg",socket.user+"因为受不了大家的摧残离开了聊天室")
})
});
使用socket.io监听连接状态,然后对数据传过来的信息进行处理
socket.emit(信息段的名称,信息内容) // 只能传给一个用户看,其他用户看不到
io.emit(信息段的名称,信息内容) // 传给多个用户
socket.broadcast.emit(信息段的名称,信息内容) // 处理当前用户,其他用户都能看到
服务端图片接收
需要安装formidable插件和内置fs插件
cnpm i formidable --save
var fs = require("fs")
var formidable = require("formidable")
图片写入到public的upload文件夹内 代码存放在index.js里面
router.post("/upload",(req,res) => {
var form = new formidable.IncomingForm();
form.uploadDir ="./public/upload/"
form.parse(req,function(err, fields,files){
if(!files.BQ) return
fs.renameSync(files.BQ.path,form.uploadDir+files.BQ.name)
res.json({
status:0,
data:files.BQ.name
})
})
})
客户端进行信息传递
let name = location.search.split("=")[1]
var socket = io('http://10.7.157.82:3000');
$("#submit").on("click",function(){
socket.emit("msg",$("#text").val())
})
// 上传图片
$("#upload").on("click",function () {
var form = new FormData()
form.append("BQ",myFile.files[0])
$.ajax({
method:"post",
url:"/upload",
data:form,
cache:false,
contentType:false,
processData:false
}).then((res) => {
console.log(res)
let str = "<img src='../upload/"+res.data+"' />"
socket.emit("msg",str)
})
})
// 开局使用socket.io 向后台发送用户名
socket.emit("msg",name)
socket.on("msg",(data) => {
$("#box").html(data+"<br />"+ $("#box").html())
})
结语
这是我做的一个十分简单的聊天系统,有很多问题还没有解决,在后面的学习中我将会慢慢克服这些困难取得更大的进步