在上一节结束后,我的整体项目文档长这样,接下来以此为基础实现一下一个广播聊天室的功能。
聊天室的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
运行后 用不同浏览器登录 就能看到广播那两栏能够显示当前登录的用户了
但是还没有具体聊天功能 和断线功能 之后再说