要在微信小程序实现聊天对话功能,回话是流式应答,这里使用了WebSocket技术。WebSocket大家应该都很熟悉,使用wx.connectSocket就可以了。这里可能需要注意下的是流式应答,后端如何发送,前端如何接收。直接上代码:
可以扫码体验:
后端关键代码:
// 定义正则表达式
String regex = "data:\\s*(\\{.*\\})";
// 创建Pattern对象
Pattern pattern = Pattern.compile(regex);
String line;
while ((line = reader.readLine()) != null) {
// 处理每条数据
// System.out.println(line);
// 创建Matcher对象
Matcher matcher = pattern.matcher(line);
// 查找匹配项
if (matcher.find()) {
String dataValue = matcher.group(1);
JSONObject jsonObject = JSON.parseObject(dataValue);
String content = jsonObject.getString("result");
Boolean end = jsonObject.getBoolean("is_end");
JSONObject data = new JSONObject();
data.put("content", content);
data.put("end", end);
data.put("type", "message");
webSocketServer.sendInfo(uid.toString(), data.toJSONString());
}
}
小程序ts代码:
data: {
messages: [], // 聊天消息列表
inputValue: '', // 输入框的值
ask: '', // 输入框的值
socketOpen: false, // WebSocket 连接状态
socketTask: null, // WebSocket 实例
answering: false, // 回答中。。。
type: 2,
credit: 0,
scrollTop: 0,
}
scrollToBottom() {
// 在需要滚动到最底部的时机
const query = wx.createSelectorQuery();
query.select('.chat-container').boundingClientRect();
query.select('.msgList').boundingClientRect();
query.exec(res => {
const scorllHeight = res[0].height;
const listHeight = res[1].height;
this.setData({
scrollTop: listHeight - scorllHeight + 92
});
});
},
async onLoad() {
const chatList = 历史聊天记录;
const chatListMessage: any = [];
if (chatList && chatList.length > 0) {
chatList.map((v: any) => {
const ask = {
sender: 'user',
avatar: '',
content: v.ask,
createTime: v.createTime,
id: v.id,
};
const answer = {
sender: 'chat',
avatar: 'xxx',
content: v.answer,
id: v.id,
}
chatListMessage.push(ask);
chatListMessage.push(answer);
})
}
// 初始化聊天消息列表,包含一条欢迎消息
const messages: any = [
{
sender: 'chat',
avatar: 'xxx',
content: `欢迎`
},
...this.data.messages,
...chatListMessage
]
// @ts-ignore
this.setData({ messages });
this.scrollToBottom();
},
//滾動到底部
bindscroll() {
// console.log(1);
},
onUnload: function () {
// 页面卸载时关闭 WebSocket 连接
this.closeSocket();
},
inputChange: function (e: any) {
// 监听输入框值的变化
this.setData({
inputValue: e.detail.value
});
},
async sendMessage() {
// 发送消息
const message = this.data.inputValue;
if (message.trim() === '') {
showToast("请输入问题");
return;
}
// 添加用户发送的消息到聊天消息列表
const newMessage = {
sender: 'user',
avatar: '',
content: message
};
//@ts-ignore
this.data.messages.push(newMessage);
// 清空输入框
this.setData({
messages: this.data.messages,
inputValue: '',
});
this.data.ask = message;
// 发送消息到 Chat
this.sendToChat(message);
},
sendToChat: function (message: any) {
if (!this.data.socketOpen) {
// 如果 WebSocket 连接未打开,则创建连接
this.createSocket();
}
this.setData({ answering: true });
// 这里请求后台
// 处理 Chat 的回答消息
const newMessage: any = {
sender: 'chat',
avatar: '',
content: ""
};
//@ts-ignore
this.data.messages.push(newMessage);
// 更新聊天消息列表并滚动到最新消息
this.setData({ messages: this.data.messages });
this.scrollToBottom();
},
createSocket: function () {
// 创建 WebSocket 连接
const socketTask = wx.connectSocket({
url: ``, // 替换为你的 WebSocket 服务器地址
success: () => {
console.log('WebSocket 连接成功');
},
fail: (error) => {
console.error('WebSocket 连接失败', error);
}
});
// 监听 WebSocket 连接打开事件
socketTask.onOpen(() => {
console.log('WebSocket 连接已打开');
this.setData({
socketOpen: true,
socketTask: socketTask
});
});
// 监听 WebSocket 接收到服务器的消息事件
socketTask.onMessage((res: any) => {
const data = JSON.parse(res.data);
// console.log(data);
if (data.type === 'message') {
// 收到 Chat 的回答消息
this.handleChatResponse(data);
}
});
// 监听 WebSocket 连接关闭事件
socketTask.onClose(() => {
console.log('WebSocket 连接已关闭');
this.setData({
socketOpen: false,
socketTask: null
});
});
// 监听 WebSocket 错误事件
socketTask.onError((error) => {
console.error('WebSocket 错误', error);
});
},
closeSocket: function () {
if (this.data.socketOpen) {
// 关闭 WebSocket 连接
this.data.socketTask.close();
}
},
handleChatResponse: async function (data: any) {
// 处理 Chat 的回答消息
const index = this.data.messages.length - 1;
this.data.messages[index].content += data.content;
// 更新聊天消息列表并滚动到最新消息
this.setData({ messages: this.data.messages });
if (data.end) {
this.setData({ answering: false, messages: this.data.messages });
this.data.ask = "";
};
this.scrollToBottom();
},
可以扫码体验: