便捷的 Java WebSocket 开发:Java WebSocket API,实现实时通信!

文摘   2024-11-09 10:25   江苏  

作者:被摸的鱼

在我多年的开发生涯中,经常遇到需要实现实时通信的场景。早期我们通常使用轮询或长轮询方式,但这些方案都存在资源浪费的问题。直到遇见了 WebSocket,它让服务器和客户端之间的双向通信变得如此优雅。今天就和大家分享如何使用 Java WebSocket API 开发实时通信应用。


一、准备工作

1.1 环境要求

  • JDK 8+

  • Maven 3.6+

  • IDE(推荐使用 IDEA)


1.2 Maven 依赖

<dependency>

    javax.websocket

    javax.websocket-api

    1.1

    provided

</dependency>

<!-- 如果是独立运行的项目,需要添加以下依赖 -->

<dependency>

    org.glassfish.tyrus

    tyrus-server

    2.1.3

</dependency>

<dependency>

    org.glassfish.tyrus

    tyrus-container-grizzly-server

    2.1.3

</dependency>

二、基本用法

2.1 创建 WebSocket 服务端

@ServerEndpoint(“/chat”)

public class ChatEndpoint {

    private static final Setsessions = Collections.synchronizedSet(new HashSet<>());

    @OnOpen

    public void onOpen(Session session) {

        sessions.add(session);

        System.out.println(“新连接加入,当前连接数:” + sessions.size());

    }

    @OnMessage

    public void onMessage(String message, Session session) {

        // 广播消息给所有连接的客户端

        for (Session s : sessions) {

            try {

                s.getBasicRemote().sendText(message);

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

    @OnClose

    public void onClose(Session session) {

        sessions.remove(session);

        System.out.println(“连接断开,当前连接数:” + sessions.size());

    }

    @OnError

    public void onError(Session session, Throwable error) {

        System.err.println(“发生错误:” + error.getMessage());

    }

}

2.2 启动 WebSocket 服务器

public class WebSocketServer {

    public static void main(String[] args) {

        Server server = new Server(“localhost”, 8025, “/websocket”, null, ChatEndpoint.class);

        try {

            server.start();

            System.out.println(“WebSocket 服务器已启动,按回车键退出...”);

            System.in.read();

        } catch (Exception e) {

            e.printStackTrace();

        } finally {

            server.stop();

        }

    }

}

三、进阶用法

3.1 自定义消息处理

public class Message {

    private String type;

    private String content;

    private String sender;

    // getter 和 setter 略

}

@ServerEndpoint(value = “/chat”, decoders = {MessageDecoder.class}, encoders = {MessageEncoder.class})

public class EnhancedChatEndpoint {

    @OnMessage

    public void onMessage(Message message, Session session) {

        switch (message.getType()) {

            case “CHAT”:

                broadcastMessage(message);

                break;

            case “JOIN”:

                handleJoin(message, session);

                break;

            default:

                // 处理其他类型消息

                break;

        }

    }

    // 其他方法略

}

3.2 心跳检测机制

@ServerEndpoint(“/chat”)

public class HeartbeatEndpoint {

    private static final long HEARTBEAT_TIMEOUT = 30000; // 30秒

    @Schedule(fixedRate = 10000) // 每10秒检查一次

    public void checkHeartbeat() {

        long now = System.currentTimeMillis();

        sessions.forEach(session -> {

            Long lastPing = (Long) session.getUserProperties().get(“lastPing”);

            if (lastPing != null && now - lastPing > HEARTBEAT_TIMEOUT) {

                try {

                    session.close(new CloseReason(

                        CloseReason.CloseCodes.GOING_AWAY,

                        “心跳超时”

                    ));

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        });

    }

}

四、实际案例

4.1 实时聊天室

@ServerEndpoint(“/chatroom”)

public class ChatRoomEndpoint {

    private static final Maprooms = new ConcurrentHashMap<>();,>

    @OnMessage

    public void onMessage(String message, Session session) {

        JsonObject jsonMessage = Json.createReader(

            new StringReader(message)).readObject();

        String roomId = jsonMessage.getString(“roomId”);

        String content = jsonMessage.getString(“content”);

        Room room = rooms.computeIfAbsent(roomId, k -> new Room());

        room.broadcast(content, session);

    }

    private static class Room {

        private final Setsessions = CopyOnWriteArraySet<>();

        public void broadcast(String message, Session sender) {

            sessions.forEach(session -> {

                try {

                    if (session != sender) {

                        session.getBasicRemote().sendText(message);

                    }

                } catch (IOException e) {

                    e.printStackTrace();

                }

            });

        }

    }

}

4.2 实时股票行情推送

@ServerEndpoint(“/stock/{symbol}”)

public class StockEndpoint {

    private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    @OnOpen

    public void onOpen(@PathParam(“symbol”) String symbol, Session session) {

        scheduler.scheduleAtFixedRate(() -> {

            try {

                // 模拟获取股票数据

                double price = 100 + Math.random() * 10;

                session.getBasicRemote().sendText(

                    String.format(“股票%s: %.2f”, symbol, price)

                );

            } catch (IOException e) {

                e.printStackTrace();

            }

        }, 0, 1, TimeUnit.SECONDS);

    }

    @OnClose

    public void onClose() {

        scheduler.shutdown();

    }

}

五、总结

Java WebSocket API 为我们提供了一种优雅的实时通信解决方案。它的核心优势在于:


  • 全双工通信,性能高效

  • API 简单直观,易于使用

  • 基于事件驱动,代码结构清晰

  • 可以轻松集成到现有项目中


在实际开发中,建议注意以下几点:


  1. 合理管理 WebSocket 连接,及时释放资源

  2. 实现心跳机制,保持连接稳定性

  3. 考虑并发安全,使用线程安全的集合

  4. 做好异常处理和日志记录

本文介绍了 Java WebSocket API 的核心特性和实践应用。在实际开发中,建议读者结合项目需求选择合适的特性,同时关注官方文档获取最新更新。如有问题,欢迎在评论区交流讨论。祝各位开发愉快!




福爷老金说
关注我了解更多养老金动态~
 最新文章