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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 使用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>

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

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
4月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
126 9
|
2天前
|
移动开发 数据挖掘 开发者
服务器发送事件(SSE)在现代Web开发中的关键作用
服务器发送事件(SSE)是HTML5标准协议,用于服务器主动向客户端推送实时数据,适合单向通信场景。相比WebSocket,SSE更简洁高效,基于HTTP协议,具备自动重连、事件驱动等特性。常见应用场景包括实时通知、新闻推送、数据分析等。通过Apipost等工具可轻松调试SSE,助力开发者构建高效实时Web应用。示例中,电商平台利用SSE实现秒杀活动通知,显著减少延迟并简化架构。掌握SSE技术,能大幅提升用户体验与开发效率。
|
13天前
|
JSON API 数据安全/隐私保护
95%开发者不知道的调试黑科技:Apipost让WebSocket开发效率翻倍的秘密
在现代Web开发中,WebSocket提供全双工通信,适用于实时交互场景,如IM系统、聊天和客服系统。尽管调试工具众多,但文档设计一直是其短板。本文介绍如何使用Apipost实现WebSocket的高效调试与文档设计。Apipost不仅简化了连接建立、消息发送等调试操作,还通过分组功能优化了消息管理。其文档设计功能支持在同一endpoint下区分业务逻辑,生成清晰易维护的文档,并可一键分享。此外,文章还提供了WebSocket实战技巧,涵盖连接保持、消息格式选择、错误处理及安全性保障等内容,助力开发者提升开发效率。
|
9天前
|
前端开发 Cloud Native Java
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
|
23天前
|
JSON API 数据安全/隐私保护
95%开发者不知道的调试黑科技:Apipost让WebSocket开发效率翻倍的秘密
在现代Web开发中,WebSocket因其全双工通信特性广泛应用于实时交互场景,但调试和文档设计工具却相对匮乏。Apipost最新推出的“调试与设计模块”解决了这一痛点,不仅简化了WebSocket的调试流程,还优化了文档设计,支持消息分组、精细化文档管理和一键分享功能,极大提升了开发效率。此外,Apipost提供了链接保持、消息格式选择、错误处理及安全性保障等实战技巧,助力开发者更好地应对WebSocket开发挑战。
|
1月前
|
网络协议 Java Shell
java spring 项目若依框架启动失败,启动不了服务提示端口8080占用escription: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to listen on another port-优雅草卓伊凡解决方案
java spring 项目若依框架启动失败,启动不了服务提示端口8080占用escription: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to listen on another port-优雅草卓伊凡解决方案
80 7
|
2月前
|
Kubernetes Java 持续交付
小团队 CI/CD 实践:无需运维,Java Web应用的自动化部署
本文介绍如何使用GitHub Actions和阿里云Kubernetes(ACK)实现Java Web应用的自动化部署。通过CI/CD流程,开发人员无需手动处理复杂的运维任务,从而提高效率并减少错误。文中详细讲解了Docker与Kubernetes的概念,并演示了从创建Kubernetes集群、配置容器镜像服务到设置GitHub仓库Secrets及编写GitHub Actions工作流的具体步骤。最终实现了代码提交后自动构建、推送镜像并部署到Kubernetes集群的功能。整个过程不仅简化了部署流程,还确保了应用在不同环境中的稳定运行。
112 9
|
3月前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
125 7
Spring Boot 入门:简化 Java Web 开发的强大工具
|
4月前
|
XML 前端开发 JavaScript
PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑
本文深入探讨了PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑;Ajax则通过异步请求实现页面无刷新更新。文中详细介绍了两者的工作原理、数据传输格式选择、具体实现方法及实际应用案例,如实时数据更新、表单验证与提交、动态加载内容等。同时,针对跨域问题、数据安全与性能优化提出了建议。总结指出,PHP与Ajax的结合能显著提升Web应用的效率和用户体验。
106 3
|
4月前
|
Java Maven Spring
Java Web 应用中,资源文件的位置和加载方式
在Java Web应用中,资源文件如配置文件、静态文件等通常放置在特定目录下,如WEB-INF或classes。通过类加载器或Servlet上下文路径可实现资源的加载与访问。正确管理资源位置与加载方式对应用的稳定性和可维护性至关重要。
105 7

热门文章

最新文章