websocket实现类似于QQ的聊天功能

使用websocket实现聊天的原因

  • http单向通讯协议,请求只能是客户端发起,且是无状态的,而websocket是双向通讯协议,可以有服务器发起也可以是客户端发起,用http实现聊天功能一般是通过轮询,但是轮询非常浪费服务器资源,而且慢,亲测过
  • 重点websocket实现简单,速度快

上代码

后台代码:采用websocket的注解

package com.xh.procourt.controller;

/**
 * Created: Administrator
 * author:xmf
 * Date:2018/7/20
 * Time:9:49
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.web.context.ContextLoader;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,value是客户端连接地址,这里定义了两个参数,和springmvc的配置指定格式的URL,
 * 映射到对应的参数是一样的
 */
@ServerEndpoint(value = "/websocket/{msg_me}")//参数格式 自定义连接标识
public class WebSocketCt {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识类似于扣扣号,map是线程不安全的
    private static Map<String, Session> webSocketSet = new HashMap<>();


    /**
     * 连接建立成功调用的方法
     *
     * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 @PathParam用来获取连接路径上的参数
     */
    @OnOpen
    public void onOpen(@PathParam(value = "msg_me") String param, Session session) {
        webSocketSet.put(param, session);     //加入map中
        addOnlineCount();           //在线数加1
        System.out.println("标识为----" + param + "----的用户连接成功,当前在线人数:::" + getOnlineCount());
        //用map构造消息格式 懒得创建消息实体类
        Map<String, Object> map = new HashMap<>();
        map.put("senderId", "system");
        map.put("msgContent", "欢迎连接");
        //由于这里使用的string的消息类型所以在这里转成json,当然还有其它消息类型
        try {
            sendMessage(JSON.toJSON(map).toString(), session);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(@PathParam(value = "msg_me") String param) {
        //根据自定义的标识移除此用户的连接
        webSocketSet.remove(param);
        subOnlineCount();   //在线数减1
        System.out.println("标识为----" + param + "----的用户断开连接成功,当前在线人数:::" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息 格式发送人_接收人_消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam(value = "msg_me") String fromId) {
        System.out.println("收到消息:::" + message.toString());
        //将消息装成json对象
        JSONObject msgObj = JSON.parseObject(message);
        //得到前台传过来的消息接收者id
        String toId = msgObj.getString("toId");
        //得到发送者标识
        String senderId = msgObj.getString("senderId");
        //得到消息内容
        String msgContent = msgObj.getString("msgContent");
        for (String s : webSocketSet.keySet()) {
            if (s.equals(toId)) {
                Session session1 = webSocketSet.get(s);
                try {
                    //用map构造消息格式 懒得创建消息实体类
                    Map<String, Object> map = new HashMap<>();
                    map.put("senderId", fromId);
                    map.put("msgContent", msgContent);
                    //由于这里使用的string的消息类型所以在这里转成json,当然还有其它消息类型
                    sendMessage(JSON.toJSON(map).toString(), session1);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return;
            }
        }
    }

    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。作用是发送消息
     *
     * @throws java.io.IOException
     * @param: message要发送的消息 session接收者的会话
     */
    public static void sendMessage(String message, Session session) throws IOException {
        session.getBasicRemote().sendText(message);
    }

    /**
     * 功能描述:用来返回当前在线的总人数
     *
     * @param:
     * @return:
     * @auther: Administrator
     * @date: 2018/7/20 9:37
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 功能描述:在线总人数加一
     *
     * @param:
     * @return:
     * @auther: Administrator
     * @date: 2018/7/20 9:37
     */
    public static synchronized void addOnlineCount() {
        WebSocketCt.onlineCount++;
    }


    /**
     * 功能描述:在线总人数减一
     *
     * @param:
     * @return:
     * @auther: Administrator
     * @date: 2018/7/20 9:38
     */
    public static synchronized void subOnlineCount() {
        WebSocketCt.onlineCount--;
    }
}

前端代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<title>简易实现点对点聊天</title>
<body>
<div>
    <input id="connectId" type="text">
    <button type="button" id="connect">连接到聊天室</button>
</div>

<div id="msgInfo">
</div>

<div style="margin-top: 50px">
    <div>
        <div><span>接收者id:</span><input type="text" id="toId">
            <span>要发送的消息:</span><input type="text" id="msg"></input>
            <button id="send" type="button">发送消息</button>
        </div>
    </div>
</div>
</body>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script>
    var websocket = null;
    var conect = null;

    //点击连接
    $("#connect").click(function () {
        //判断当前连接是否为空
        if (websocket != null) {
            alert("您已经连接了,请不要重复连接!");
            return;
        }
        //自定义的唯一标识,如果两个人输入的连接标识相同则会覆盖原来这个标识对应的连接,这里只是为了简单演示
        var connectId = $("#connectId").val();
        if (connectId == null || connectId == '') {
            alert("请先输入您的连接标识!");
            return
        }
        //开始连接
        // 首先判断是否 支持 WebSocket
        if ('WebSocket' in window) {
            //路径ws + ip + port + 自定义路径
            conect = connectId;
            websocket = new WebSocket("ws://192.168.10.20:8080//websocket/" + connectId);
        } else {
            alert("浏览器不支持连接!")
            return;
        }

        // 打开时
        websocket.onopen = function (evnt) {
            console.log("  websocket.onopen  ");
            alert("连接成功!");
        };

        // 处理消息时
        websocket.onmessage = function (evnt) {
            //将消息转成json格式
            var msg = JSON.parse(evnt.data);
            $("#msgInfo").append("<p>收到--" + msg.senderId + "--给您发消息:<font color='red'>" + msg.msgContent + "</font></p>");
            console.log("  websocket.onmessage   ");
        };

        websocket.onerror = function (evnt) {
            websocket == null;
            console.log("  websocket.onerror  ");
        };

        websocket.onclose = function (evnt) {
            console.log("  websocket.onclose  ");
            websocket.close();
            alert("连接关闭!");
        };
    });

    //发送消息
    $("#send").click(function () {
        //先判断是否连接
        if (websocket == null) {
            alert("您还没有连接!!!");
            return;
        }

        //接收者id
        var toId = $("#toId").val();
        //发送的消息内容
        var msg = $("#msg").val();
        if (toId == null || toId == '') {
            alert("请先输入接收者");
            return;
        }
        if (msg == null || msg == '') {
            alert("消息不能为空!!!");
            return;
        }

        //发送消息
        //构造消息的json格式
        var msgJson = {
            senderId: conect,
            msgContent: msg,
            toId: toId
        };
        websocket.send(JSON.stringify(msgJson));
    });
</script>
</html>

运行效果截图

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值