私信(聊天)功能 ajax长轮询实现

前言


私信(聊天)功能,有一点是不能忽略的,那就是消息的实时发送与实时接收,否则的话就直接退化成为留言板功能了。

之前我在论坛中有问到这个实现的方法,我考虑了websocket 和 ajax 长轮询这两个方法,很多人也有说websocket比较消耗资源。最终在权衡服务器和客户端的情况下,使用了ajax方法(websocket不会写


ajax的能干什么?

使用Ajax技术网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面,这使得程序能够更快地回应用户的操作。(节选自百度百科

简单的来说,使用ajax,页面不刷新就可以验证用户名是否存在。在页面不刷新的情况下向服务器端发送一个请求,在得到服务器的响应后,把结果重新传到页面上并进行显示。

哪里用到了ajax?

在这里插入图片描述
尝试在百度输入一个候选词,然后下方会弹出推荐,使用键盘上下进行选择。在你还没有按下回车的时候,页面的内容就已经变了,而如果是刷新的话,文本框中的内容就应该已经没有了,但是使用ajax就可以有这样的效果。

后端

  • Spring boot
  • Mybatis
  • MySQL

前端

  • HTML
  • CSS
  • JS
  • jquery
  • ajax

数据交互

前后端通过JSON数据交互。

整体实现思路

  1. 列表中选择一个自己要聊天的对象
  2. 使用 ajax 显示消息
  3. 发送消息 ,使用 ajax 避免刷新,实时显示
  4. 长轮询,每 2 秒发送一次查询请求并实时显示消息
  5. 确保每次直达底部的最新消息

实时接收消息

@ResponseBody
    @GetMapping("/userCenter/chat/{receiver}")
    public String chatWithOthers(@PathVariable("receiver") String receiver,
                                    Model model, HttpSession session)  {
        //搜索用户的聊天状态
        User user = (User) session.getAttribute("loginUser");
        String sender = user.getUserName();
        List<ChatListDTO> chatLists = chatListService.list(sender);
        model.addAttribute("chatLists", chatLists);

        if (userMapper.selectUserByName(receiver)==null){
            model.addAttribute("noUser","noUser");
            return "";
        }

        //更改消息数的时候,receiver是发送者,而sender是接收者
        messageMapper.updateMessageCount(receiver,sender);
        //查找属于sender的两人会话
        List<MessageDTO> list = messageService.messagesList(sender, receiver, sender);
        JSONArray array= JSONArray.parseArray(JSON.toJSONString(list));
        return array.toJSONString();
    }

html前端

这里是从后端查询了当前用户的聊天列表,并进行遍历显示。

<ul>
                <li th:id="${item.chatList.others}" th:each="item : ${chatLists}" class="chat-item">
                    <!--                    th:href="@{'/userCenter/communicate/'+${item.chatList.others}}"-->
                    <span th:onclick="chat([[${item.chatList.others}]])">
                        <img th:src="${item.others.imgUrl}" class="chat-img">
                        <span class="chat-user">
                            [[${item.chatList.others}]]
                        </span>
                    </span>
                    <span class="chat-time"
                          th:text="${#dates.format(item.chatList.lastReplyTime,'yyyy-MM-dd HH:mm')}">
                    </span>
                </li>
            </ul>

js 和 ajax

name 已经在 onclick 里面传过。

整体思路:往后端发送请求查询,然后往前端返回 JSON ,然后遍历显示。

鉴于会有新信息,要实时接收新信息,就可以使用 setInterval( 一个显示的 function (),2000),这表示两秒查询一次并回显。

function chat(name) {
        $("#chat_content").val("");
        $("#receiver_name").attr("value", name.toString());
        $(".chat-item").removeClass("background");
        $("#" + name).addClass("background");
        var others = name;
        var totol;
        var chatArea = $("#chat_area");
        var time = 0;
        $("#noChat").hide();
        $("#chat").css("display", "block");
        $.ajax({
            type: "get",
            url: "/userCenter/chat/" + others,
            dataType: "json",
            success: function (data) {

                chatArea.html("");

                data = JSON.stringify(data);
                var jsonData = JSON.parse(data);
                totol = jsonData.length;
                for (var i = 0; i < totol; i++) {
                    var msg = jsonData[i];
                    var sender = msg.sender.userName;
                    var imgUrl = msg.sender.imgUrl;
                    var content = msg.message.content;
                    var div_class;
                    var img_class;
                    var msg_time = msg.message.gmtCreate;
                    if (msg_time - time > 60000) {
                        time = msg_time;
                        msg_time = new Date(msg_time).toLocaleString().replace(/:\d{1,2}$/, ' ');
                    } else {
                        msg_time = "";
                    }
                    if (sender != others) {
                        //如果我是发送者
                        div_class = "sender";
                        img_class = "reply-img";
                    } else {
                        div_class = "receiver";
                        img_class = "receiver-img";
                    }
                    var message = "<br style=\"line-height: 60px\">" +
                        "<p style='text-align: center'>"
                        + msg_time
                        + "</p>" +
                        "<div class=\"msg-div\">" +
                        "<div class=" + div_class + ">" +
                        "<img src= "
                        + imgUrl +
                        "  class=" + img_class + ">" +
                        "<div class=\"content-msg\">"
                        + content +
                        "</div>" +
                        "</div></div>";
                    chatArea.append(message);
                    chatArea.scrollTop(9999);
                }
            },
            error: function () {
                alert("错误 ")
            }
        })
        setInterval(function () {
            var times = 0;
            $.ajax({
                type: "get",
                url: "/userCenter/chat/" + others,
                dataType: "json",
                success: function (data) {
                    data = JSON.stringify(data);
                    var times = 0;
                    var jsonData = JSON.parse(data);
                    var newTotal = jsonData.length;
                    if (newTotal == totol) {
                        console.log("无新消息");
                    } else {
                        chatArea.html("");
                        totol = newTotal;
                        for (var i = 0; i < totol; i++) {
                            var msg = jsonData[i];
                            var sender = msg.sender.userName;
                            var imgUrl = msg.sender.imgUrl;
                            var content = msg.message.content;
                            var div_class;
                            var img_class;
                            var msg_time = msg.message.gmtCreate;
                            if (msg_time - times > 60000) {
                                times = msg_time;
                                msg_time = new Date(msg_time).toLocaleString().replace(/:\d{1,2}$/, ' ');
                            } else {
                                msg_time = "";
                            }
                            if (sender != others) {
                                //如果我是发送者
                                div_class = "sender";
                                img_class = "reply-img";
                            } else {
                                div_class = "receiver";
                                img_class = "receiver-img";
                            }
                            console.log(img_class);
                            var message = "<br style=\"line-height: 60px\">" +
                                "<p style='text-align: center'>"
                                + msg_time
                                + "</p>" +
                                "<div class=\"msg-div\">" +
                                "<div class=" + div_class + ">" +
                                "<img src= "
                                + imgUrl +
                                "  class=" + img_class + ">" +
                                "<div class=\"content-msg\">"
                                + content +
                                "</div>" +
                                "</div></div>";
                            $("#chat_area").append(message);
                            $("#chat_area").scrollTop(9999);
                        }
                    }
                },
                error: function () {
                    alert("错误 ")
                }
            })
        }, 2000);
    }

实时发送消息

因为显示消息是使用ajax实现的,所以我们就可以通过一个标签来获得聊天对象的名字(id)。在显示聊天信息的时候已经把下面的值改变了。

<span id="receiver_name" value=""></span>

HTML

这里的表单最开始使用的是form,但是因为调用ajax的时候的 success 和 error 都没有执行,就把 form 变成了 div,所有的样式还是和form一样的。

<div id="chat_form" class="padding-top-30px">
                                <textarea id="chat_content" name="chatContent" class="form-control"
                                  placeholder="给对方打个招呼吧!" cols="20" rows="8"></textarea>
                                <br>
                                <button type="submit" onclick="sendMsg()"  id="content_submit"
                                        class="btn btn-info btn-primary btn-right">提交
                                </button>
                            </div>

js

   function sendMsg() {
     var chatContent =$("#chat_content");
     var receiverName = $("#receiver_name").attr("value");
     var content = chatContent.val();
     var chatArea = $("#chat_area");
     $.ajax({
         type: "post",
         url: "/chat/" + receiverName,
         data:{
             "content": content
         },
         async:false,
         dataType: "text",
         success:function (data) {
             chatContent.val('');
             var jsonData = JSON.stringify(data);
             var msg1 = jsonData.message;
             var msgContent = msg1.content;
             var sender1 = jsonData.sender;
             var msg_time = jsonData.gmtCreate;
             msg_time = new Date(msg_time).toLocaleString().replace(/:\d{1,2}$/, ' ');
             var imgUrl = sender1.imgUrl;
             var div_class = "sender";
             var img_class = "reply-img";
             var message = "<br style=\"line-height: 60px\">" +
                 "<p style='text-align: center'>"
                 + msg_time
                 + "</p>" +
                 "<div class=\"msg-div\">"
                 "<div class=" + div_class + ">" +
                 "<img src= "
                 + imgUrl +
                 "  class=" + img_class + ">" +
                 "<div class=\"content-msg\">"
                 + msgContent +
                 "</div>" +
                 "</div></div>";

             chatArea.append(message);

             chatArea.scrollTop(9999);
         },
         error:function (data) {
             data = JSON.stringify(data);
             alert("failed " + data);
         }
     })
 }

ajax对应的方法

@ResponseBody
@PostMapping(value = "/chat/{receiver}")
    public String sendMassage(@PathVariable("receiver") String receiver,
                              @RequestParam String content,
                              HttpSession session) {
        MessageDTO dto = new MessageDTO();
        User user = (User) session.getAttribute("loginUser");
        String sender = user.getUserName();
        Long current;
        //创建两个人的消息
        for (int i = 1; i <= 2; i++) {
            Message msg = new Message();
            current = System.currentTimeMillis();
            String id = sender + "-" + receiver + "-" + current;
            msg.setId(id);
            msg.setSender(sender);
            msg.setReceiver(receiver);
            msg.setHasRead(0);
            msg.setContent(content);
            msg.setGmtCreate(current);
            if (i == 1) {
                msg.setForUser(sender);
                User senderUser = userMapper.selectUserByName(sender);
                dto.setSender(senderUser);
                dto.setMessage(msg);
            } else {
                msg.setForUser(receiver);
                User receiveUser = userMapper.selectUserByName(receiver);
                dto.setSender(receiveUser);
            }
            //插入消息
            messageMapper.insertMsg(msg);
        }

        if (chatListMapper.selectChatId(sender, receiver) == null)
        //插入到会话列表
        {
            for (int i = 1; i <=2 ; i++) {
                ChatList chatList = new ChatList();
                current = System.currentTimeMillis();
                chatList.setId(sender + current);
                chatList.setLastReplyTime(current);
                //循环为两个人的对话赋值
                if (i == 1){
                    chatList.setMe(sender);
                    chatList.setOthers(receiver);

                }
                else{
                    chatList.setMe(receiver);
                    chatList.setOthers(sender);
                }
                chatListMapper.insertChatList(chatList);
            }
        }else {
            current = System.currentTimeMillis();
            chatListMapper.updateLastReplyTime(sender,receiver,current);
        }

        String json = JSON.toJSONString(dto);
        return json;
    }

注意点

在 ajax 中,把DataType设置成“josn”的时候,传往后台的数据 ——“你好”,会自动变成 “content = 你好”, 暂时不清楚是什么原因导致的。在更改了DataType = “text” 后,就可以正常的往后台传送参数了。

效果图

在这里插入图片描述

有问题请看这里

有疑问的话可以在评论区留言或者私信作者。

整个系统是一个 医学科普 + 论坛 , 如果需要作为毕业设计的话可以联系作者。

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久影

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值