You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Java、Sockets与Ajax的客户端-服务器-客户端通信实现问题

实现带HTML UI的聊天客户端+服务器Socket通信,以及用户双向聊天的方案

嘿,我来帮你梳理下怎么搞定这个需求——从HTML客户端发消息到Java服务器,再扩展到用户间的双向聊天,一步步来:

一、先搞定HTML客户端与服务器的实时通信

首先得明确:浏览器没法直接用原生TCP Socket(除非是特定受限环境),所以WebSocket是最适合实时聊天的选择,它基于HTTP握手建立连接后,能保持双向实时通信,完美匹配你的需求。

1. 前端HTML/JS客户端实现

先写个极简的聊天界面,包含消息展示区、输入框和发送按钮:

<!DOCTYPE html>
<html>
<head>
    <title>简易聊天框</title>
    <style>
        #messageContainer { 
            height: 320px; 
            border: 1px solid #eee; 
            padding: 10px; 
            overflow-y: auto; 
            margin-bottom: 15px;
            background-color: #f9f9f9;
        }
        .msg-item { margin: 8px 0; padding: 6px; border-radius: 4px; }
        .my-msg { background-color: #e3f2fd; text-align: right; }
        .other-msg { background-color: #fff; text-align: left; }
        #inputArea { display: flex; gap: 10px; }
        #msgInput { flex: 1; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
        button { padding: 8px 16px; border: none; background-color: #2196f3; color: white; border-radius: 4px; cursor: pointer; }
    </style>
</head>
<body>
    <div id="userSetup">
        <input type="text" id="username" placeholder="输入你的用户名">
        <button id="connectBtn">连接聊天</button>
    </div>
    <div id="chatArea" style="display: none;">
        <div id="messageContainer"></div>
        <div id="inputArea">
            <input type="text" id="targetUser" placeholder="发给谁?">
            <input type="text" id="msgInput" placeholder="输入消息...">
            <button id="sendBtn">发送</button>
        </div>
    </div>

    <script>
        let socket;
        let currentUsername;

        // 连接服务器
        document.getElementById('connectBtn').addEventListener('click', () => {
            currentUsername = document.getElementById('username').value.trim();
            if (!currentUsername) {
                alert("请输入用户名!");
                return;
            }
            // 连接本地WebSocket服务器,端口根据你的配置调整
            socket = new WebSocket('ws://localhost:8080/chat');
            
            socket.onopen = () => {
                // 连接成功后告知服务器自己的用户名
                socket.send(`USER:${currentUsername}`);
                document.getElementById('userSetup').style.display = 'none';
                document.getElementById('chatArea').style.display = 'block';
            };

            // 接收服务器消息
            socket.onmessage = (event) => {
                const msgContainer = document.getElementById('messageContainer');
                const msgDiv = document.createElement('div');
                // 判断是不是自己发的消息,做样式区分
                const isMyMsg = event.data.startsWith(`我 ->`);
                msgDiv.className = isMyMsg ? 'msg-item my-msg' : 'msg-item other-msg';
                msgDiv.textContent = event.data;
                msgContainer.appendChild(msgDiv);
                // 自动滚动到最新消息
                msgContainer.scrollTop = msgContainer.scrollHeight;
            };

            // 处理连接关闭
            socket.onclose = () => {
                alert("与服务器断开连接");
                document.getElementById('chatArea').style.display = 'none';
                document.getElementById('userSetup').style.display = 'block';
            };
        });

        // 发送消息
        document.getElementById('sendBtn').addEventListener('click', sendMsg);
        // 支持回车发送
        document.getElementById('msgInput').addEventListener('keypress', (e) => {
            if (e.key === 'Enter') sendMsg();
        });

        function sendMsg() {
            const targetUser = document.getElementById('targetUser').value.trim();
            const msgContent = document.getElementById('msgInput').value.trim();
            if (!targetUser || !msgContent) return;
            // 按约定格式发送:目标用户名|消息内容
            socket.send(`${targetUser}|${msgContent}`);
            document.getElementById('msgInput').value = '';
        }
    </script>
</body>
</html>

2. Java WebSocket服务器实现

这里用Java EE的原生WebSocket API(如果用Spring Boot会更简单,核心逻辑一致),实现连接管理、消息转发:

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint("/chat")
public class ChatServer {
    // 用线程安全的Map保存「用户名-会话」映射
    private static final Map<String, Session> userSessionMap = new ConcurrentHashMap<>();

    // 客户端连接时触发
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("新客户端接入,会话ID:" + session.getId());
    }

    // 收到客户端消息时触发
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        // 解析消息:如果是USER开头,就是用户登录
        if (message.startsWith("USER:")) {
            String username = message.substring(5);
            userSessionMap.put(username, session);
            // 给当前用户发送登录成功提示
            session.getBasicRemote().sendText("系统:你已以[" + username + "]身份进入聊天室");
            System.out.println("用户[" + username + "]登录成功");
            return;
        }

        // 普通聊天消息,格式:目标用户名|消息内容
        String[] msgParts = message.split("\\|", 2);
        if (msgParts.length != 2) {
            session.getBasicRemote().sendText("系统:消息格式错误,请使用「目标用户名|消息内容」格式");
            return;
        }
        String targetUser = msgParts[0];
        String msgContent = msgParts[1];
        String senderUsername = getUsernameBySession(session);

        // 查找目标用户的会话
        Session targetSession = userSessionMap.get(targetUser);
        if (targetSession == null) {
            session.getBasicRemote().sendText("系统:用户[" + targetUser + "]不在线或不存在");
            return;
        }

        // 给目标用户发消息
        targetSession.getBasicRemote().sendText(senderUsername + ":" + msgContent);
        // 给发送者回显已发送的消息
        session.getBasicRemote().sendText("我 -> " + targetUser + ":" + msgContent);
    }

    // 客户端断开连接时触发
    @OnClose
    public void onClose(Session session) {
        // 移除离线用户的映射
        userSessionMap.entrySet().removeIf(entry -> entry.getValue().equals(session));
        System.out.println("客户端断开连接,会话ID:" + session.getId());
    }

    // 异常处理
    @OnError
    public void onError(Session session, Throwable error) {
        System.err.println("会话[" + session.getId() + "]发生错误:");
        error.printStackTrace();
    }

    // 通过会话反向查找用户名
    private String getUsernameBySession(Session session) {
        for (Map.Entry<String, Session> entry : userSessionMap.entrySet()) {
            if (entry.getValue().equals(session)) {
                return entry.getKey();
            }
        }
        return "未知用户";
    }
}

二、核心逻辑说明

  1. HTML客户端:通过WebSocket与服务器建立连接,发送用户名完成登录,然后按约定格式发送目标用户+消息内容,同时接收服务器转发的消息并展示。
  2. Java服务器:维护在线用户的会话映射,收到登录请求时绑定用户名与会话;收到聊天消息时解析目标用户,找到对应会话后转发消息,同时给发送者回显。
  3. 双向通信实现:服务器作为中转,把用户A的消息转发给用户B,反之亦然,本质是通过「用户名-会话」的映射精准投递消息。

三、测试小技巧

打开两个浏览器窗口,分别输入不同的用户名(比如「用户1」和「用户2」),然后在输入框里指定目标用户发送消息,就能看到双向聊天的效果啦~

内容的提问来源于stack exchange,提问作者Alex Sparrow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:42:53