java开发之使用websocket实现web客户端与服务器之间的实时通讯

简介: 使用websocket实现web客户端与服务器之间的实时通讯。以下是个简单的demo。

第一次写博客,有写的不好的地方欢迎大家指点。
使用websocket实现web客户端与服务器之间的实时通讯。以下是个简单的demo。


import java.util.Date;

public class WebSocketMessage {

    /**
     * 发送者ID
     */
    private String senderId;

    /**
     * 接受者ID, 如果为0, 则发送给所有人
     */
    private String receiverId;

    /**
     * 会话内容
     */
    private String messageContent;

    /**
     * 发送时间
     */
    private Date sendTime;

    public String getSenderId() {
        return senderId;
    }

    public void setSenderId(String senderId) {
        this.senderId = senderId;
    }

    public String getReceiverId() {
        return receiverId;
    }

    public void setReceiverId(String receiverId) {
        this.receiverId = receiverId;
    }

    public String getMessageContent() {
        return messageContent;
    }

    public void setMessageContent(String messageContent) {
        this.messageContent = messageContent;
    }

    public Date getSendTime() {
        return sendTime;
    }

    public void setSendTime(Date sendTime) {
        this.sendTime = sendTime;
    }

}

import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("webSocket")
public class WebSocketController {

    @RequestMapping(value = "messagePage/{userID}")
    public ModelAndView messagePage(@PathVariable String userID, HttpServletResponse response) {
        ModelAndView mav = new ModelAndView();
        mav.addObject("userID", userID);
        mav.setViewName("web_socket");
        return mav;
    }
}

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import com.alibaba.fastjson.JSON;
import com.utime.facade.model.systemplate.WebSocketMessage;

@ServerEndpoint("/webSocketServer/{userID}")
public class WebSocketServer {
    // 连接客户端数量
    private static int onlineCount = 0;
    // 所有的连接客户端
    private static Map<String, WebSocketServer> clients = new ConcurrentHashMap<String, WebSocketServer>();
    // 当前客户端连接的唯一标示
    private Session session;
    // 当前客户端连接的用户ID
    private String userID;

    /**
     * 客户端连接服务端回调函数
     * 
     * @param userID 用户ID
     * @param session 会话
     * @throws IOException
     */
    @OnOpen
    public void onOpen(@PathParam("userID") String userID, Session session) throws IOException {
        this.userID = userID;
        this.session = session;

        addOnlineCount();
        clients.put(userID, this);
        System.out.println("WebSocket日志: 有新连接加入!当前在线人数为" + getOnlineCount());
    }

    @OnClose
    public void onClose() throws IOException {
        clients.remove(userID);
        subOnlineCount();
        System.out.println("WebSocket日志: 有一连接关闭!当前在线人数为" + getOnlineCount());
    }

    /**
     * 接受到来自客户端的消息
     * 
     * @param message
     * @throws IOException
     */
    @OnMessage
    public void onMessage(String message) throws IOException {
        System.out.println("WebSocket日志: 来自客户端的消息:" + message);
        WebSocketMessage webSocketMessage = JSON.parseObject(message, WebSocketMessage.class);

        // 发送消息给所有客户端
        if ("0".equals(webSocketMessage.getReceiverId())) {
            for (WebSocketServer item : clients.values()) {
                item.session.getAsyncRemote().sendText(webSocketMessage.getMessageContent());
                System.out.println("WebSocket日志: ID为"+ webSocketMessage.getSenderId() +"的用户给ID为"+ item.userID +"的客户端发送:" + webSocketMessage.getMessageContent());
            }
        } else {    // 发送消息给指定ID的客户端
            for (WebSocketServer item : clients.values()) {
                if (item.userID.equals(webSocketMessage.getReceiverId())){
                    // 发消息给指定客户端
                    item.session.getAsyncRemote().sendText(webSocketMessage.getMessageContent());
                    System.out.println("WebSocket日志: ID为"+ webSocketMessage.getSenderId() +"的用户给ID为"+ item.userID +"的客户端发送:" + webSocketMessage.getMessageContent());
                    if (!webSocketMessage.getSenderId().equals(webSocketMessage.getReceiverId())) {
                        // 发消息给自己
                        this.session.getAsyncRemote().sendText(webSocketMessage.getMessageContent());
                        System.out.println("WebSocket日志: ID为"+ webSocketMessage.getSenderId() +"的用户给ID为"+ this.userID +"的客户端发送:" + webSocketMessage.getMessageContent());
                    }
                    break;
                }
            }
        }
    }
    
    /**
     * 服务端报错了
     * 
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("WebSocket日志: 发生错误");
        error.printStackTrace();
    }
    
    /**
     * 客户端连接数+1
     */
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }
    
    /**
     * 客户端连接数-1
     */
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized Map<String, WebSocketServer> getClients() {
        return clients;
    }
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"  prefix="fmt"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fun"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> 
<c:set var="baseurl" value="${pageContext.request.contextPath}/"></c:set>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>web_socket</title>

<script type="text/javascript" src="${baseurl}static/js/jquery-2.1.1.js"></script>
<style type="text/css">
    .connector {width: 500px;}
</style>
</head>
<body>
    Welcome
    <br/>
    <input id="text" type="text"/>
    <button onclick="sendToOne(10008)">发消息给个人</button>
    <button onclick="sendToAll(0)">发消息给所有人</button>
    <hr/>
    <button onclick="closeWebSocket()">关闭WebSocket连接</button>
    <hr/>
    <div id="message"></div>
</body>
<script type="text/javascript">
    var websocket = null;
    var host = document.location.host;
    
    //判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        console.info("浏览器支持Websocket");
        websocket = new WebSocket('ws://'+host+'/${baseurl}/webSocketServer/${userID}');
    } else {
        console.info('当前浏览器 Not support websocket');
    }
    
    //连接发生错误的回调方法
    websocket.onerror = function() {
        console.info("WebSocket连接发生错误");
        setMessageInnerHTML("WebSocket连接发生错误"); 
    }
    
    //连接成功建立的回调方法
    websocket.onopen = function() {
        console.info("WebSocket连接成功");
        setMessageInnerHTML("WebSocket连接成功"); 
    } 
    
    //接收到消息的回调方法 
    websocket.onmessage = function(event) {
        console.info("接收到消息的回调方法");
        console.info("这是后台推送的消息:"+event.data);
        setMessageInnerHTML(event.data); 
        console.info("webSocket已关闭!");
    }
    
    //连接关闭的回调方法 
    websocket.onclose = function() {
        setMessageInnerHTML("WebSocket连接关闭");
    }
    
    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function() {
        closeWebSocket();
    }
    
    //关闭WebSocket连接 
    function closeWebSocket() {
        websocket.close();
    }
    
    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }
    
    //发送消息给其他客户端
    function sendToOne(receiverId) {
        var messageContent = document.getElementById('text').value;
        var message = {};
        message.senderId = "${userID}";
        message.receiverId = receiverId;
        message.messageContent = messageContent;
        websocket.send(JSON.stringify(message));
    }
    
    //发送消息给所有人
    function sendToAll() {
        var messageContent = document.getElementById('text').value;
        var message = {};
        message.senderId = "${userID}";
        message.receiverId = "0";
        message.messageContent = messageContent;
        websocket.send(JSON.stringify(message));
    }
</script>
</html>

写这个的目的只是为了自己做个记录。
写的不好,后面会慢慢完善。

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
6月前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
7月前
|
消息中间件 人工智能 Java
抖音微信爆款小游戏大全:免费休闲/竞技/益智/PHP+Java全筏开源开发
本文基于2025年最新行业数据,深入解析抖音/微信爆款小游戏的开发逻辑,重点讲解PHP+Java双引擎架构实战,涵盖技术选型、架构设计、性能优化与开源生态,提供完整开源工具链,助力开发者从理论到落地打造高留存、高并发的小游戏产品。
|
8月前
|
安全 Java 数据库
Java 项目实战病人挂号系统网站设计开发步骤及核心功能实现指南
本文介绍了基于Java的病人挂号系统网站的技术方案与应用实例,涵盖SSM与Spring Boot框架选型、数据库设计、功能模块划分及安全机制实现。系统支持患者在线注册、登录、挂号与预约,管理员可进行医院信息与排班管理。通过实际案例展示系统开发流程与核心代码实现,为Java Web医疗项目开发提供参考。
391 2
|
7月前
|
存储 Java 关系型数据库
Java 项目实战基于面向对象思想的汽车租赁系统开发实例 汽车租赁系统 Java 面向对象项目实战
本文介绍基于Java面向对象编程的汽车租赁系统技术方案与应用实例,涵盖系统功能需求分析、类设计、数据库设计及具体代码实现,帮助开发者掌握Java在实际项目中的应用。
284 0
|
6月前
|
算法 Java Go
【GoGin】(1)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
gin 框架中采用的路优酷是基于httprouter做的是一个高性能的 HTTP 请求路由器,适用于 Go 语言。它的设计目标是提供高效的路由匹配和低内存占用,特别适合需要高性能和简单路由的应用场景。
554 4
|
10月前
|
缓存 JavaScript 前端开发
鸿蒙5开发宝藏案例分享---Web开发优化案例分享
本文深入解读鸿蒙官方文档中的 `ArkWeb` 性能优化技巧,从预启动进程到预渲染,涵盖预下载、预连接、预取POST等八大优化策略。通过代码示例详解如何提升Web页面加载速度,助你打造流畅的HarmonyOS应用体验。内容实用,按需选用,让H5页面快到飞起!
|
10月前
|
JavaScript 前端开发 API
鸿蒙5开发宝藏案例分享---Web加载时延优化解析
本文深入解析了鸿蒙开发中Web加载完成时延的优化技巧,结合官方案例与实际代码,助你提升性能。核心内容包括:使用DevEco Profiler和DevTools定位瓶颈、四大优化方向(资源合并、接口预取、图片懒加载、任务拆解)及高频手段总结。同时提供性能优化黄金准则,如首屏资源控制在300KB内、关键接口响应≤200ms等,帮助开发者实现丝般流畅体验。
|
前端开发 JavaScript Shell
鸿蒙5开发宝藏案例分享---Web页面内点击响应时延分析
本文为鸿蒙开发者整理了Web性能优化的实战案例解析,结合官方文档深度扩展。内容涵盖点击响应时延核心指标(≤100ms)、性能分析工具链(如DevTools时间线、ArkUI Trace抓取)以及高频优化场景,包括递归函数优化、网络请求阻塞解决方案和setTimeout滥用问题等。同时提供进阶技巧,如首帧加速、透明动画陷阱规避及Web组件初始化加速,并通过优化前后Trace对比展示成果。最后总结了快速定位问题的方法与开发建议,助力开发者提升Web应用性能。
|
10月前
|
JSON 开发框架 自然语言处理
【HarmonyOS Next之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(三)
本文主要介绍了应用开发中的三大核心内容:生命周期管理、资源限定与访问以及多语言支持。在生命周期部分,详细说明了应用和页面的生命周期函数及其触发时机,帮助开发者更好地掌控应用状态变化。资源限定与访问章节,则聚焦于资源限定词的定义、命名规则及匹配逻辑,并阐述了如何通过 `$r` 引用 JS 模块内的资源。最后,多语言支持部分讲解了如何通过 JSON 文件定义多语言资源,使用 `$t` 和 `$tc` 方法实现简单格式化与单复数格式化,为全球化应用提供便利。
341 104
下一篇
开通oss服务