Tomcat学习笔记(3)--WebSocket(2)--WebSocket实现进入聊天室与广播信息

在上一节结束后,我的整体项目文档长这样,接下来以此为基础实现一下一个广播聊天室的功能。
聊天室的html没找到特别好的,所以就拿黑马程序员的教程页面八!
教程地址:https://www.bilibili.com/video/BV1dJ411N7Um?p=53

在这里插入图片描述

写代码

在这里插入图片描述
新建一个包 和一个类 作用放处理对话的WebSocket

先写ChartSocket的 中途需要多加一个类 叫做GetHttpSessionConfigurator
注释以及我的理解以及全部写入到注释中了

//ChartSocket的代码
package cn.CakeCN.webSocket;

import cn.CakeCN.util.MessageUtil;

import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;

@ServerEndpoint(value = "/websocket",configurator = GetHttpSessionConfigurator.class)
public class ChartSocket {

    private Session session;
    private HttpSession httpSession;

    //这里储存了所有在系统中登录了的用户的HttpSession信息,以及对于的ChartSocket实例 (EndPoint类)
    //每一个浏览器客户端与服务端建立的一个连接都产生一个chartSocket的实例,
    //这些实例要用一种方式记录下来,用的就是Map
    //key用的是httpSession,也就是客户端与服务端的唯一会话ID
    private static Map<HttpSession,ChartSocket> onlineUsers = new HashMap<HttpSession,ChartSocket>();
    private static int onlineUserCount = 0;
    //这里注解@OnOpen 表示当有会话访问/websocket时 调用下面的函数


    @OnOpen
    public void opOpen(Session session, EndpointConfig config){
        //1.实例中,记录WebSocket的会话信息对象Session
        this.session=session;

        //2.获取当前用户的HttpSession信息,需要借助ServerEndpoint中的配置
        // 使用configurator指定的一个类
        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());

        this.httpSession = httpSession;//将获取到的HttpSession保存在实例中

        //打印日志
        System.out.println("当前登录用户: "+httpSession.getAttribute("username")+", Endpoint : " +hashCode());

        //3.记录当前登录用户的信息以及对应的EndPoint信息(自己这个ChartSocket实例)到  MAP中
        if (httpSession.getAttribute("username")!=null){
            onlineUsers.put(httpSession,this);
        }

        //以上就完成了在服务端记录用户数据的功能
        //下面需要做的是 将所有的用户信息以广播的形式发回给客户端,这样所有客户端才知道当前有多少人在线
        //4.获取当前所有登录用户
        String names = getNames();

        //5.组装消息 json格式 :{"data": "名单字符串names" ,"toName": "","fromName":"",'type':"user" }
        String message = MessageUtil.getContent(MessageUtil.TYPE_USER,"","",names);

        //6.广播发送
        //关于发送信息:
        //用RemoteEndpoint实现,其实例由Session维护
        //上一句话的意思就是RemoteEndpoint不用咱自己管,只需要用就行
        //可以用Session.getBasicRemote获取同步消息发送的实例,
        //然后调用其sendXXX()方法就可以发送消息
        //用Session.getAsyncRemote获取异步消息发送实例 这些以后学
        //这样一句简单的session.getBasicRemote().sendText(""); 就成功为当前的会话客户端发送了一条消息
        //为所有客户端广播 用上Map当然也不难

        broadCastAllUsers(message);


        //7.记录当前用户登录数
        incUserCount();

    }

    //发送广播消息
    private void broadCastAllUsers(String message) {
        for (HttpSession hs : onlineUsers.keySet()){
            try{
            onlineUsers.get(hs).session.getBasicRemote().sendText(message);
            }
            catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    //获取在线用户的名单
    private String getNames() {
        //从记录所有当前登录用户的Map中 获取UserName
        String names="";
        if (onlineUsers.size()>0){
            for (HttpSession hs : onlineUsers.keySet()){
                String username =  (String)  hs.getAttribute("username");
                names+=username+',';
            }
        }
        //去掉最后一个逗号:获取name的从0开始长度为names的长度-1  的子串
        return  names.substring(0,names.length()-1);
    }


    //synchronized 确保“线程安全” 具体以后再学
    public synchronized void incUserCount(){
        onlineUserCount++;
    }
    public synchronized void decUserCount(){
        onlineUserCount--;
    }
    public int getOnlineUserCount(){
        return onlineUserCount;
    }

}

//GetHttpSessionConfigurator

package cn.CakeCN.webSocket;

import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator {

    //这里重写握手时的代码,就是为了在握手时获取到HttpSession
    @Override
    public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {

        //这个我们需要获取的HttpSession就包含在request参数中 直接强制转化
        HttpSession httpSession = (HttpSession) request.getHttpSession();

        //下面是要将获取到的这个httpSession传递给ChartSocket实例
        //用到的这个config 它的类型就是ServerEndpointConfig 是在ChartSocket一开始的注解中用configurator传入的数据
        //并且这个config在OnOpen()函数中,是作为参数传入进去的
        config.getUserProperties().put(HttpSession.class.getName(),httpSession);
        //(这里第一个参数随意起名字,只要在ChartSocket的OnOpen()中能够对应识别)
    }
}

添加一个工具类 用来做数据到json的转化
在这里插入图片描述

//MessageUtil
package cn.CakeCN.util;

import com.alibaba.fastjson.JSON;

import java.util.HashMap;
import java.util.Map;

public class MessageUtil {

    public final static String TYPE = "type";
    public final static String DATA = "data";
    public final static String FROM_NAME = "fromName";
    public final static String TO_NAME = "toName";

    public final static String TYPE_MESSAGE = "message";
    public final static String TYPE_USER = "user";


    //组装消息, 然后返回一个json格式的消息数据
    public static String getContent(String type, String fromName, String toName, String content) {
        Map<String, Object> userMap = new HashMap<String, Object>();
        userMap.put(MessageUtil.TYPE, type);
        userMap.put(MessageUtil.DATA, content);
        userMap.put(MessageUtil.FROM_NAME, fromName);
        userMap.put(MessageUtil.TO_NAME, toName);

        String jsonMsg = JSON.toJSONString(userMap);
        return jsonMsg;
    }
}

chat页面外部链接了一些资源 css、js 、image等等:

这里直接就放b站视频下面的度云链接八!
配套资料:https://pan.baidu.com/s/1_lIoUoGhbYnqrmAFzwXJrA 提取码:smwt

运行后 用不同浏览器登录 就能看到广播那两栏能够显示当前登录的用户了
但是还没有具体聊天功能 和断线功能 之后再说

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值