要在微信小程序实现聊天对话功能,回话是流式应答,这里使用了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-ignorethis.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-ignorethis.data.messages.push(newMessage);// 清空输入框this.setData({messages: this.data.messages,inputValue: '',});this.data.ask = message;// 发送消息到 Chatthis.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-ignorethis.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();},
可以扫码体验: