最简单的用websocket实现聊天室

1.后台代码,采用注解的方式



/**
 * 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();
    }

    /**
     * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。作用是发送消息
     * @param: message要发送的消息 session接收者的会话
     * @throws java.io.IOException
     */
    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--;
    }
}

2.前端代码

<!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) {
                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>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值