目录
添加依赖
添加WebSocketConfig配置
新建component文件夹,加入WebSocketServer
加入WebSocketLook
chat.html核心js代码
chatList的代码
两个人在同一聊天室
WebSocket 是基于TCP/IP协议,独立于HTTP协议的通信协议。
WebSocket 是双向通讯,有状态,客户端一(多)个与服务端一(多)双向实时响应(客户端 ⇄ 服务端)。
WebSocket 是应用在浏览器的 Socket (是 Socket 模型接口的实现),Socket 是一个网络通信接口 (通信规范)。
org.springframework.boot
spring-boot-starter-websocket
com.alibaba
fastjson
${fastjson.version}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
/**
* 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
package com.example.pipayshopapi.component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author websocket服务
*/
@ServerEndpoint(value = "/imserver/{userId}")
@Component
public class WebSocketServer {
private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
// 注入查看聊天列表的服务
private WebSocketLook webSocketLook=WebSocketLook.getInstance();
/**
* 记录当前在线连接数
*/
public static final Map sessionMap = new ConcurrentHashMap<>();
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
// 保存当前用户session
sessionMap.put(userId, session);
System.out.println(sessionMap.size());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(Session session, @PathParam("userId") String userId) {
// 移除当前用户session
sessionMap.remove(userId);
}
/**
* 收到客户端消息后调用的方法
* 后台收到客户端发送过来的消息
* onMessage 是一个消息的中转站
* 接受 浏览器端 socket.send 发送过来的 json数据
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session, @PathParam("userId") String userId) {
JSONObject obj = JSON.parseObject(message);
String toUserId = obj.getString("to"); // to表示发送给哪个用户,比如 admin
String text = obj.getString("text"); // 发送的消息文本 hello
Session toSession = sessionMap.get(toUserId); // 根据 to用户名来获取 session,再通过session发送消息文本
if (toSession != null) {
// 服务器端 再把消息组装一下,组装后的消息包含发送人和发送的文本内容
// {"from": "zhang", "text": "hello"}
JSONObject jsonObject = new JSONObject();
jsonObject.put("from", userId); // from 是 zhang
jsonObject.put("text", text); // text 同上面的text
this.sendMessage(jsonObject.toString(), toSession);
log.info("发送给用户username={},消息:{}", toUserId, jsonObject.toString());
} else {
// 发送消息给可能在聊天室外面的人
webSocketLook.sendMsgLook(userId,toUserId,text);
}
// 存入数据库
}
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
/**
* 服务端发送消息给客户端
*/
private void sendMessage(String message, Session toSession) {
try {
log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
toSession.getBasicRemote().sendText(message);
} catch (Exception e) {
log.error("服务端发送消息给客户端失败", e);
}
}
}
package com.example.pipayshopapi.component;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author websocket服务
*/
@ServerEndpoint(value = "/imlook/{userId}")
@Component
public class WebSocketLook {
private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
private static WebSocketLook webSockerLook = null;
/**
* 记录当前在线连接数
*/
public static final Map sessionMap = new ConcurrentHashMap<>();
public static WebSocketLook getInstance() {
if (webSockerLook == null) {
webSockerLook = new WebSocketLook();
}
return webSockerLook;
}
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
// 保存当前用户session
sessionMap.put(userId, session);
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(Session session, @PathParam("userId") String userId) {
// 移除当前session
sessionMap.remove(userId);
}
/**
* 收到客户端消息后调用的方法
* 后台收到客户端发送过来的消息
* onMessage 是一个消息的中转站
* 接受 浏览器端 socket.send 发送过来的 json数据
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session, @PathParam("userId") String userId) {
}
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
/**
* 发送消息给聊天室外面的人
* @param userId
* @param toUserId
* @param text
*/
public void sendMsgLook(String userId, String toUserId, String text) {
// 判断是否接收方是否在线并且在聊天室外
Session toSession = sessionMap.get(toUserId); // 根据 to用户名来获取 session,再通过session发送消息文本
// 接收方在聊天室外
if (toSession != null) {
// 服务器端 再把消息组装一下,组装后的消息包含发送人和发送的文本内容
// {"from": "zhang", "text": "hello"}
JSONObject jsonObject = new JSONObject();
jsonObject.put("from", userId); // from 是 zhang
jsonObject.put("text", text); // text 同上面的text
jsonObject.put("to",toUserId); // 接收方
this.sendMessage(jsonObject.toString(), toSession);
log.info("发送给用户username={},消息:{}", toUserId, jsonObject.toString());
}
// 接收方离线中,不操作,
}
/**
* 服务端发送消息给客户端
*/
private void sendMessage(String message, Session toSession) {
try {
log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
toSession.getBasicRemote().sendText(message);
} catch (Exception e) {
log.error("服务端发送消息给客户端失败", e);
}
}
}
chat
chatList
发送信息给13
12发送14,14不在聊天室里面
14收到12的信息