首先是express服务器端的实现,利用ws库
第一步,下载ws模块
npm i ws
第二步,粘贴代码
var express = require('express');
var router = express.Router();
var {addressBookModel} = require("../model/model/lzx")
导入ws模块
const WebSocket = require("ws");
let clients=[]; //存所有连接上的用户
// 创建WebSocket服务器
const wss = new WebSocket.Server({ port: 8080 });
// 监听连接建立事件
wss.on("connection", function(socket) {
console.log("WebSocket连接已建立");
// 监听接收到客户端发送的消息
socket.on("message", function(message) {
console.log("接收到户端发送的消息:" + message);
//每个客户端都存上自己发来的phone做为唯一的id
//连接上后就压进数组
clients.push({id:message,ws:socket})
});
// 监听连接关闭事件
socket.on("close", function() {
console.log("WebSocket连接已关闭");
});
});
// 当有人发送消息的时候
router.post('/sendMsg', (req, res) =>{
//前端传过来的数据,otherId是当前要接受消息的人的id,message是消息主体,_id是当前发送消息的人的id,otherName是当前发送消息人的项目
let {otherId,message,_id,otherName} = req.body
console.log(otherId);
const datalist = {
_id,
message,
otherName,
}
const Medatalist = {
_id,
message,
}
console.log(datalist);
//循环遍历 找到你要发送的人 他的id 就发送
clients.forEach((ele) =>{
console.log('eleid',ele.id);
console.log(otherId);
if(otherId==ele.id){
ele.ws.send(JSON.stringify(datalist));
}
});
//发送给自己客户端的数据
res.send(Medatalist)
})
//获取我们的通讯录
router.get('/getAddressBooks',async function (req, res, next) {
let {_id} = req.query
let data = await addressBookModel.find({uid:_id})
res.send({
code:200,
data
});
});
module.exports = router;
然后是客户端的实现
第一步,配置网络权限
module.json5文件中
{
"name": "ohos.permission.INTERNET",
},
注意!!!!文章中的this.id.slice(1,this.id.length-1)是给我们从首选项获取的数据进行了一次切割,因为我们首选存储后再读取出来可能会有多一个引号的问题,就例如""aaa"",也就是说全部都成了两个引号,所以需要切割
//引入鸿蒙官方的websocket模块
import webSocket from '@ohos.net.webSocket';
//映入鸿蒙官方的通知模块,就是一发消息,我们的手机上通知的那个模块
import NotificationManager from '@ohos.notificationManager';
//引入axios
import axios from '../../http/index'
//引入路由
import router from '@ohos.router';
//引入首选项存储,这里我是利用首选项存储了我们当前用户的id,用户名,头像等
import SharePre from '../../util/SharePre'
//引入鸿蒙官方提供的文件管理,用来存储聊天记录
import common from '@ohos.app.ability.common';
//文件操作模块
import fs from '@ohos.file.fs';
@Entry
@Component
struct Chat{
//读取上级传来的params,这里我的params中是要聊天的那个人的信息
@State params:any = router.getParams()
@State msg:string = ""
@State username:string = ""
@State _id:string = ""
@State imgPath:string = ""
//存储聊天记录
@State chatRecords:Array<{_id:string,message:string}> = []
//获取上下文,用于存储聊天记录
private context = getContext(this) as common.UIAbilityContext
//声明一个ws,用于websocket的使用
private ws
async aboutToAppear(){
//获取首选项存储的id,用户名和头像
this._id = await SharePre.getPreferenceValue('MyPreferences','_id','666') as string
this.username = await SharePre.getPreferenceValue('MyPreferences','username','666') as string
this.imgPath = await SharePre.getPreferenceValue('MyPreferences','imgPath','666') as string
//创建websocket连接
this.ws = webSocket.createWebSocket()
this.ws.connect("ws://59.110.165.22:8080")
this.ws.on("open",(err,value)=>{
if(!err){
console.log("连接成功")
//在这里直接先像服务器发送一次请求,先发送一次请求是为了将id添加到后端的用户列表中
this.ws.send(this._id.slice(1,this._id.length-1))
}
})
this.ws.on("message",(err,value)=>{
if(!err){
console.log("收到消息"+value)
this.chatRecords.push(JSON.parse(value))
//这里打印的是我们聊天记录的存储位置
console.log("我是涛的文件",this.context.filesDir)
//存储聊天记录
let file = fs.openSync(this.context.filesDir+`/${this.params._id}.txt`,fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
fs.write(file.fd,JSON.stringify(this.chatRecords))
fs.close(file)
//收到消息时通知
let notificationRequest = {
id: 1,
content: {
contentType: NotificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT, // 普通文本类型通知
normal: {
title: JSON.parse(value).otherName,
text: JSON.parse(value).message,
}
}
}
NotificationManager.publish(notificationRequest, (err) => {
if (err) {
console.error(`[ANS] failed to publish, error[${err}]`);
return;
}
console.info(`[ANS] publish success`);
});
}
})
this.ws.on("close",(err,value)=>{
if(!err){
console.log("连接断开")
}
})
//读取聊天记录,从我们存储的聊天记录文件中获取聊天记录 let file = fs.openSync(this.context.filesDir+`/${this.params._id}.txt`,fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE) let buf = new ArrayBuffer(2048) let leng = fs.readSync(file.fd,buf,{offset:0}) this.chatRecords = JSON.parse(String.fromCharCode.apply(null,new Uint8Array(buf.slice(0,leng)))) fs.closeSync(file)
}
async sendData(){
console.log('params_id',this.params._id)
try {
//给后端发送请求,发送数据
const response = await axios.post("lzx/sendMsg",{otherId:this.params._id,message:this.msg,_id:this._id.slice(1,this._id.length-1),otherName:this.username.slice(1,this.username.length-1)});
console.log(JSON.stringify(response));
this.chatRecords.push({"_id":this._id.slice(1,this._id.length-1),message:response.data.message})
//这里打印的是我们聊天记录的存储位置
console.log("我是涛的文件",this.context.filesDir)
//存储聊天记录
let file = fs.openSync(this.context.filesDir+`/${this.params._id}.txt`,fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
fs.write(file.fd,JSON.stringify(this.chatRecords))
fs.close(file)
//发送后清空聊天数据
this.msg = ""
} catch (error) {
console.error(JSON.stringify(error));
}
}
@Builder popupBuilder() {
Row({ space: 2 }) {
Image($r("app.media.icon")).width(24).height(24).margin({ left: 5 })
Text('This is Custom Popup').fontSize(15)
}.width(200).height(50).padding(5)
}
@Builder Title(){
Row(){
Text(this.params.username)
NavRouter(){
Text("...")
//这里我们做了一个跳转的操作,跳转到我们对方的详细信息页面,对于聊天没有帮助,可以不看
.onClick(()=>{
router.pushUrl(
{
url:"pages/MyMessage/ChatSettings",
params:this.params
}
)
})
}
}.width("90%").justifyContent(FlexAlign.SpaceAround)
}
build(){
Navigation() {
Column(){
Column(){
List({space:10}){
ForEach(this.chatRecords,(item)=>{
ListItem(){
if(item._id==this._id.slice(1,this._id.length-1)){
Row(){
Row(){
Text(item.message)
}
.width(150)
.height(50)
.backgroundColor("#FFB6C1")
.borderRadius(15)
Text(":")
//使用时需要进行切片,因为默认会多加一层引号,如果不切片,出不来效果
Image(this.imgPath.slice(1,this.imgPath.length-1))
.width(50)
.height(50)
.borderRadius(50)
}
.width("100%")
.justifyContent(FlexAlign.End)
}else if(item._id==this.params._id){
Row(){
Image(this.params.imgPath)
.width(50)
.height(50)
.borderRadius(50)
.onClick(()=>{
router.pushUrl(
{
url:"pages/MyMessage/ChatSettings",
params:this.params
}
)
})
Text(":")
Row(){
Text(item.message)
}
.width(150)
.height(50)
.backgroundColor("#FFF")
.borderRadius(15)
}
.width("100%")
}
}
})
}.width("100%").height("100%").backgroundColor("#eee")
}
.width("100%")
.height("93%")
Row(){
TextInput({placeholder:"请输入您想要发送的内容",text:this.msg})
.width("80%")
.height(50)
.onChange((e)=>{
this.msg = e
})
Button("发送")
.height(50)
.width(70)
//发送消息
.onClick(()=>{
this.sendData()
})
}
.width("100%")
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.SpaceBetween)
}
.title(this.Title())
.titleMode(NavigationTitleMode.Mini)
}
}

861

被折叠的 条评论
为什么被折叠?



