使用WebSocket构建实时群聊系统
WebSocket 提供了浏览器与服务器之间的全双工通道,非常适合做实时多人聊天。相比传统 HTTP 轮询,它延迟更低、流量更小,服务器也能主动推送消息。
功能清单
- 用户进入房间时,全员收到"欢迎提示"。
- 任何用户发送的文字,立即广播给所有人。
- 用户关闭页面或刷新,全员收到"离开提示"。
项目结构
chat-room/
├─ src/
│ └─ ChatEndpoint.java
├─ WebContent/
│ ├─ index.html
│ ├─ chat.js
│ └─ style.css
└─ WEB-INF/
└─ web.xml
前端实现
index.html 仅负责引入样式和脚本,核心逻辑在 chat.js:
// chat.js
const socket = new WebSocket('ws://localhost:8080/chat-room/chat');
socket.onopen = () => {
const nick = prompt('请输入昵称');
if (nick) socket.send(JSON.stringify({ type: 'join', nick }));
};
socket.onmessage = evt => {
const chatBox = document.getElementById('chatBox');
chatBox.insertAdjacentHTML('beforeend', evt.data);
chatBox.scrollTop = chatBox.scrollHeight;
};
function sendMsg() {
const input = document.getElementById('msgInput');
const text = input.value.trim();
if (!text) return;
socket.send(JSON.stringify({ type: 'chat', text }));
input.value = '';
}
document.getElementById('msgInput').addEventListener('keydown', e => {
if (e.key === 'Enter') sendMsg();
});
window.addEventListener('beforeunload', () => socket.close());
后端实现
使用 Java EE 的 WebSocket API,只需一个端点类即可:
package ws;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint("/chat")
public class ChatEndpoint {
private static final Map<Session, String> users = new ConcurrentHashMap<>();
private static final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss");
@OnOpen
public void onConnect(Session session) {
// 等待第一条 join 消息
}
@OnMessage
public void onText(String json, Session session) throws IOException {
Msg msg = Msg.fromJson(json);
if ("join".equals(msg.type)) {
users.put(session, msg.nick);
broadcast(render("系统", msg.nick + " 加入聊天室"));
return;
}
if ("chat".equals(msg.type)) {
String nick = users.get(session);
broadcast(render(nick, msg.text));
}
}
@OnClose
public void onClose(Session session) throws IOException {
String nick = users.remove(session);
if (nick != null) {
broadcast(render("系统", nick + " 离开聊天室"));
}
}
private void broadcast(String html) throws IOException {
for (Session s : users.keySet()) {
if (s.isOpen()) s.getBasicRemote().sendText(html);
}
}
private String render(String user, String content) {
return String.format(
"<div class='bubble'><span class='time'>%s</span>" +
"<strong>%s</strong>: %s</div>",
LocalTime.now().format(fmt), user, content
);
}
private static class Msg {
String type;
String nick;
String text;
static Msg fromJson(String json) {
return new com.google.gson.Gson().fromJson(json, Msg.class);
}
}
}
部署
将项目打成 war 包或直接放入 Tomcat 的 webapps 目录,启动后访问:
http://localhost:8080/chat-room
即可体验实时群聊。