gitee项目地址
使用websocket实现单聊和群聊;使用CameraX仿微信拍视频和拍照片、Android原生技术实现文件查看器和音乐播放器
nodejs、flutter、MySql、Android
若用户没有账号的情况下,用户注册账户。注册成功之后就登录账号。进入主页,查询所有用户(注:为了简化过程,这里不实现好友添加,好友删除,即注册了账户,大家就是可以互相聊天的好朋友)。用户点击某一个用户,进入聊天室,用户可以发送消息(暂时为文本、表情),也可以接受用户发来的消息;接受到的消息记录在本地,若用户不在线(即未连接上websocket),朋友发送的消息就存储在服务器。只要用户一上线,就发送给他所有存储在服务器的消息。最后用户可以登出账号。
https://www.processon.com/view/link/6482d583629200782585e337
CREATE TABLE `my_wechat_message_cache` (
`messageId` varchar(45) CHARACTER SET utf8mb3 NOT NULL COMMENT '消息Id',
`senderId` varchar(45) CHARACTER SET utf8mb3 DEFAULT NULL COMMENT '发送者Id',
`receiverId` varchar(45) CHARACTER SET utf8mb3 DEFAULT NULL COMMENT '接受者Id',
`messageContent` varchar(45) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '消息内容',
`sendDate` varchar(45) CHARACTER SET utf8mb3 DEFAULT NULL COMMENT '发送时间',
`senderAvatar` varchar(200) CHARACTER SET utf8mb3 DEFAULT NULL COMMENT '发送头像',
PRIMARY KEY (`messageId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
CREATE TABLE `my_wechat_user` (
`userId` varchar(20) NOT NULL COMMENT '用户Id',
`userName` varchar(45) DEFAULT NULL COMMENT '用户昵称',
`tel` varchar(20) DEFAULT NULL COMMENT '电话号码',
`password` varchar(45) DEFAULT NULL COMMENT '密码',
`avatar` varchar(200) DEFAULT 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg' COMMENT '头像',
PRIMARY KEY (`userId`),
UNIQUE KEY `tel_UNIQUE` (`tel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='仿微信用户表';
var util = require('./shared_util.js')
const express = require('express')
const app = express()
app.use(express.json())
const port = 3000
var mysql = require('mysql')
var connection = mysql.createConnection({
host: 'localhost',
user: 'bilibili',
password: '123',
database: 'bilibili'
})
app.get('/', (req, res) => {
res.send('服务3000')
})
//注册
app.post('/wechat/register', (req, res) => {
let userId = (new Date()).valueOf()
let tel = req.body.tel
let userName = req.body.userName
let password = req.body.password
if (util.strIsNotEmpty(tel) && util.strIsNotEmpty(userName) && util.strIsNotEmpty(password)) {
///查询是否存在用户
connection.query(
`SELECT * FROM my_wechat_user where tel = \"${tel}\"`,
function (err, rows, fields) {
if (err) throw err
if (rows.length != 0) {
res.send({
"code": 400,
"message": "用户存在"
})
} else {
///新增用户
connection.query(
`INSERT INTO my_wechat_user (\`userId\`, \`userName\`, \`tel\`, \`password\`) VALUES (\"${userId}\", \"${userName}\", \"${tel}\", \"${password}\")`,
function (err, rows, fields) {
if (err) throw err
res.send({
"code": 0,
"message": "注册成功"
})
}
)
}
}
)
} else {
res.send({
"code": 500,
"message": "输入不能为空"
})
}
})
//登录
app.post('/wechat/login', (req, res) => {
let tel = req.body.tel
let password = req.body.password
if (util.strIsNotEmpty(tel) && util.strIsNotEmpty(password)) {
///查询是否存在用户
connection.query(
`SELECT * FROM my_wechat_user where tel = \"${tel}\" && password = \"${password}\"`,
function (err, rows, fields) {
if (err) throw err
if (rows.length != 0) {
res.send({
"code": 0,
"message": `欢迎${rows[0].userName}`,
"data": {
"userId": rows[0].userId, //用户id
"userName": rows[0].userName, //用户昵称
"avatar": rows[0].avatar, //头像
}
})
} else {
res.send({
"code": 400,
"message": "用户不存在或者密码错误"
})
}
}
)
} else {
res.send({
"code": 500,
"message": "输入不能为空"
})
}
})
//查询所有用户列表
app.get('/wechat/users', (req, res) => {
connection.query(`SELECT userId, userName, avatar FROM my_wechat_user`, function (err, rows, fields) {
if (err) throw err
res.send({
"code": 0,
"message": "获取用户列表成功",
"data": rows
})
})
})
app.listen(port, () => {
connection.connect()
console.log('服务3000启动...')
})
///连接数据
var mysql = require('mysql')
var connection = mysql.createConnection({
host: 'localhost',
user: 'bilibili',
password: '123',
database: 'bilibili',
charset: "utf8mb4", //表情符四个字节
collate: "utf8mb4_unicode_ci",
})
///websocket服务器
const ws = require('nodejs-websocket')
///记录当前的在线的用户
var connectionMap = new Map()
const server = ws.createServer(conn => {
///获取连接进来的用身份户信息
let token = JSON.parse(conn.headers.token)
console.log("websocket connect:" + token.userId + "连进来了...")
///加到map
connectionMap.set(token.userId, conn)
///查询待发的消息并发送
let receiverId = token.userId
connection.query(`SELECT * FROM my_wechat_message_cache where receiverId = \"${receiverId}\"`,
function (err, rows, fields) {
if (err) throw err
rows.forEach(receivedData => {
sendCacheMsg(receivedData, receiverId)
})
}
)
///用户发送消息至服务
conn.on('text', data => {
/*
接受消息格式
{
"users": ["user001", "user002"], ///发送给谁的列表
"msg": "你好", ///发送内容
"sender": "user002", ///发送人
"date": "时间戳", ///时间
"avatar": "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg" ///网络图片头像
}
*/
try {
let receivedData = JSON.parse(data)
// console.log(receivedData)
sendUserMsg(receivedData)
} catch (e) {
console.log(data)
console.log(e)
}
})
///用户断开连接
conn.on('close', data => {
connectionMap.delete(token.userId)
console.log("websocket close:" + token.userId + "断开连接")
})
///出错
conn.on('error', data => {
console.log("websocket error:" + token.userId + "出错了")
})
})
server.listen(4000, () => {
console.log("启动服务器")
})
///广播所有连接的对象
var broadcast = (msg) => {
server.connections.forEach(item => {
item.send(msg)
})
}
///发送消息
var sendUserMsg = (receivedData) => {
///发送人Id
let senderId = receivedData.sender;
///待发送人名单
let users = receivedData.users
///发送给名单里面的人
users.forEach(user => {
let conn = connectionMap.get(user)
///判断是否在线,否则消息为待发送
if (conn != null) {
/*
发送消息格式
{
"msg": "你好", //发送内容
"sender": "user001" //发送者
"receiver": "user001" //接受者
"date": "123" //发送时间
"avatar": "..." //头像
}
*/
let sendData =
`
{
\"msg\": \"${receivedData.msg}\",
\"sender\": \"${receivedData.sender}\",
\"receiver\": \"${user}\",
\"date\": ${receivedData.date},
\"avatar\": \"${receivedData.avatar}\"
}
`
conn.send(sendData)
} else {
///如果不在线,则消息进入待发队列
let messageContent = receivedData.msg
// console.log(messageContent)
let sendDate = receivedData.date
let senderAvatar = receivedData.avatar
users.forEach(receiverId => {
let messageId = (new Date()).valueOf() + senderId + receiverId
// console.log("接受者")
// console.log(receiverId)
connection.query(
`INSERT INTO my_wechat_message_cache (\`messageId\`, \`senderId\`, \`receiverId\`, \`messageContent\`, \`sendDate\`, \`senderAvatar\`) VALUES (\"${messageId}\", \"${senderId}\", \"${receiverId}\", \"${messageContent}\", \"${sendDate}\", \"${senderAvatar}\")`,
function (err, rows, fields) {
if (err) throw err
}
)
})
}
})
}
///发送待发消息后删除待发记录
var sendCacheMsg = (readyMsg) => {
server.connections.forEach(item => {
///用户身份验证消息
let token = JSON.parse(item.headers.token)
///接受者Id
let receiverId = token.userId;
if (readyMsg.receiverId == receiverId) {
let sendData =
`
{
\"msg\": \"${readyMsg.messageContent}\",
\"sender\": \"${readyMsg.senderId}\",
\"receiver\": \"${readyMsg.receiverId}\",
\"date\": ${readyMsg.sendDate},
\"avatar\": \"${readyMsg.senderAvatar}\"
}
`
item.send(sendData)
///删除记录
let messageId = readyMsg.messageId
connection.query(`DELETE FROM my_wechat_message_cache WHERE (\`messageId\` = \"${messageId}\")`, function (err, rows, field) {
if (err) throw err
})
}
})
}
{
"users": ["1686038201239"],
"msg": "你好",
"sender": "1686038558394",
"date": "1686038558394",
"avatar": "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg"
}