后端部分
由于本人后端开发经验较少,本项目也是本着学习的态度简单实现了一下,应该会有不少不合理之处,请指教。
建表
1.room表,用于存放用户新建的房间信息,字段为
- id:主键。
- name:房间名称。
- introduce:房间简介
- manageId:房主id
- password:房间密码
- code:随机生成的房间号
- isDelete:房间是否被删除,假删标识
2.user表,用于存放用户信息,字段为
- id:主键
- username:用户名
- password:密码
3.user_room中间表,用于关联房间与用户的关系,字段为
- id:主键
- roomId:房间id
- userId:用户id
- isDelete:是否删除
4.histroy历史记录表,存放聊天记录,字段为
- id:主键
- message:消息内容(此处有坑,下面详细介绍)
- sendUser:发送人id
- sendusername:发送人姓名(这里偷个懒,直接前端传姓名,合理的做法应该是后端自己查)
- time:发送时间,查询历史记录时根据时间排序
搭建node服务
结构目录
初始化package.json
node init -y
安装必要的插件
yarn add express --save //用于创建创建Web服务器
yarn add cors --save //cors跨域
yarn add body-parser --save //解析post请求
yarn add mysql --save //连接数据库
创建server.js
const express = require("express")
const app = express()
const cors = require("cors")
const bodyParser = require("body-parser")
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}));
app.use(cors());
const mysql = require("mysql")
连接数据库
const connection = mysql.createConnection({
host:'你的服务器地址',
user:"一般为root",
password:"你的mysql密码",
database:"你的数据库",
charset:'utf8mb4' //注意连接池字符集
})
connection.connect()
头部信息
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",'3.2.1');
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
做完以上部分就可愉快的写接口啦!例如登录:
app.post('/user/login',function(req,res){
let username = req.body.username
let password = req.body.password
const sql = "select * from user where username ='"+username+"' and password ='"+password+"'"
connection.query(sql,function(err,result){
if(err){
console.log('/user/login:',err)
return;
}
if(result.length > 0){
res.send({
data:result[0],
status:0
})
}else{
res.send({
status:1,
message:"The username or password is incorrect"
})
}
});
})
socket部分
创建websocket.js
const ws = require("nodejs-websocket")
const createServer = ()=>{
let server = ws.createServer(connection=>{
connection.on('text', (result)=> {
//这里处理客户端发送的消息,例如心跳
connection.sendText(JSON.stringify({type:null,remark:"接收心跳"}))
})
connection.on('connect', function(code) {
// console.log('开启连接', code)
})
connection.on('close', function(code) {
// console.log('关闭连接', code)
})
connection.on('error', function(code) {
// console.log('异常关闭', code)
})
}).listen(8012)
return server
}
module.exports = createServer()
主要的接口以及逻辑
-
用户登录、注册
用户提交用户名、密码,接口校验数据库是否存在用户名,如果没有,进行注册;如果有,校验密码是否正确。登录或注册成功进入聊天室。这里只是简单实现了一下,正确用户体系应该更为复杂,密码也应该加密。
-
获取用户已进入的聊天室
通过中间表查询,通过inner join查询出房间的对应信息,接口判断房间是否需要密码,返回添加字段isPassword。
-
房间验证、详情
选择房间后,通过isPassword判断房间是否需要密码,如果需要,用户提交密码验证是否正确。进入房间后获取房间详情。
-
创建房间
用户提交表单,生成数字、字符、英文组成的18位房间号,插入数据库。
-
删除房间
只有管理员可以删除房间,前端通过房间详情的manageId和用户的id控制删除按钮的显隐,同时接口校验是否是管理员,将room的isDelete改为1
-
退出房间
将中间表的isDelete改为1,如果用户是管理员,删除房间。
-
保存消息
将用户发送的信息保存到history表,同时通过socket推送给当前房间的用户。
坑
字符集
实现前期只考虑了文字消息,被帮忙测试的朋友吐槽了一番后,加上了表情功能,发现insert语句报错了,上网一查发现,emjio表情是4个字节,如果数据库或表为utf8编码,只能存储3字节,会导致插入报错,于是修改数据库、表的字符集为utf8mb4。
ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
但是依然插入失败,检查后发现,还需要修改连接池的charset,修改后插入成功,其实也称不上是坑,怪自己太嫩。
结尾
暂时先写到这儿吧,后面有优化或新功能会持续更新。应该有很多不合理的地方,有些功能甚至只是为了实现而实现,还得去多学习一些服务器、后端相关的知识。