(java)websocket服务的两种实现方式

news2024/12/23 13:06:53

1.基于java注解实现websocket服务器端

1.1需要的类

1.1.1服务终端类

用java注解来监听连接@ServerEndpoint、连接成功@OnOpen、连接失败@OnClose、收到消息等状态@OnMessage

1.1.2配置类

把spring中的ServerEndpointExporter对象注入进来

2.1代码示例

2.1.1 maven配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.heima</groupId>
    <artifactId>ws-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
           <version>2.7.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-websocket -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>2.7.14</version>
        </dependency>



    </dependencies>

</project>

2.1.2 WsServerEndpoint类

package com.heima;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/***
 * 监听websocket地址  /myWs
 */
@ServerEndpoint("/myWs")
@Component
@Slf4j
@EnableScheduling
public class WsServerEndpoint {

    static Map<String,Session> map = new ConcurrentHashMap<String,Session>();

    /***
     * 连接建立时执行的操作
     * @param session
     */
    @OnOpen
    public void onOpen(Session session)
    {
        map.put(session.getId(),session);
        log.info("websocket is open");
    }

    /***
     * 收到客户端消息执行的操作
     * @param text
     */
    @OnMessage
    public String OnMessage(String text)
    {
        log.info("收到了一条信息"+text);
        return "已收到你的信息" ;
    }

    /***
     * 连接关闭时执行的操作
     * @param session
     */
    @OnClose
    public void OnClose(Session session)
    {
        map.remove(session.getId());
        log.info("连接关闭时执行的操作");
    }

    /***
     * 向客户端发送信息
     */
    @Scheduled(fixedRate = 2000)
    public void sendMsg() throws IOException {
        for (String key : map.keySet())
        {
            map.get(key).getBasicRemote().sendText("你好,你好");
        }
    }
}

2.1.3 WebSocketConfig

package com.heima;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {


    @Bean
 public ServerEndpointExporter serverEndpointExporter()
 {
     return new ServerEndpointExporter();
 }



}

2.1.3 前端测试代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>wsClient</title>
</head>
<body>

<script>
     // 创建websocket
    let ws = new WebSocket("ws://localhost:8080/myWs")
     //向服务器发送hello
    ws.onopen=function (){
        ws.send("hello")
    }
    //监听数据ws://localhost:8080/myWs
    ws.onmessage=function (message){
        console.log(message.data)
    }
</script>
</body>
</html>

2.1.4测试结果

2.1.4.1 当打开浏览器时

2.1.4.2 当关闭浏览器时

2.1.4.3 当刷新浏览器的时候

2.基于spring提供的类和接口刷新websocket服务器端

2.1:HttpSessionHandShakeInter 握手拦截器

package com.spring;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

import java.util.Map;

/***
 * 握手拦截器
 */
@Component
@Slf4j
public class MyWsInterceptor extends HttpSessionHandshakeInterceptor {


    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        log.info(request.getRemoteAddress().toString()+"开始握手");
        return super.beforeHandshake(request, response, wsHandler, attributes);
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {
         log.info(request.getRemoteAddress().toString()+"完成握手");
        super.afterHandshake(request, response, wsHandler, ex);
    }
}

2.2  MyWsHandler 主处理程序

sessionbean封装类
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.web.socket.WebSocketSession;

@Data
@AllArgsConstructor
public class SessionBean {
    private WebSocketSession webSocketSession;
    private Integer clientId;
}
 主处理程序
package com.spring;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.server.Session;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

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

/***
 * webSocket 主处理程序
 */
@Component
@Slf4j
@EnableScheduling
public class MyWsHandler extends AbstractWebSocketHandler {
    //map有并发线程问题  所以用ConcurrentHashMap
    private static Map<String, SessionBean> map ;
    //id有并发问题 所以用Integer的安全类型
    private static AtomicInteger clientIdMaker;
    static {

        map = new ConcurrentHashMap<>();
        clientIdMaker=new AtomicInteger(0);
    }
    //连接建立
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        super.afterConnectionEstablished(session);
        //将session 进一步封装  id采用的是自增
        SessionBean sessionBean = new SessionBean(session, clientIdMaker.getAndIncrement());
        map.put(session.getId(),sessionBean);
        log.info(map.get(session.getId()).getClientId()+"建立了连接");
    }

    //收到消息
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        super.handleTextMessage(session, message);
        log.info(map.get(session.getId()).getClientId()+":"+message.getPayload());
    }

    //传输异常
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        super.handleTransportError(session, exception);

        if (session.isOpen())
        {
            session.close();
        }
        map.remove(session.getId());

    }
    //连接关闭
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        super.afterConnectionClosed(session, status);
        log.info(map.get(session.getId()).getClientId()+"关闭连接");
    }

    /***
     * 向客户端发送信息
     */
    @Scheduled(fixedRate = 2000)
    public void sendMsg() throws IOException {
        for (String key : map.keySet())
        {
            map.get(key).getWebSocketSession().sendMessage(new TextMessage("hello," +
                    "spring socket"));
        }
    }
}

2.3 WebSocketConfigurer 注册拦截器和主处理程序以及监听路径

package com.spring;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import javax.annotation.Resource;

@Configuration
@EnableWebSocket
public class MyWsConfig implements WebSocketConfigurer {
    @Resource
    private MyWsHandler wsHandler;
    @Resource
    private MyWsInterceptor wsInterceptor;
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(wsHandler,"/myWs1").addInterceptors(wsInterceptor).setAllowedOriginPatterns("*");
    }
}

2.4 前端测试

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>wsClient</title>
</head>
<body>

<script>
     // 创建websocket
    let ws = new WebSocket("ws://localhost:8080/myWs1")
     //向服务器发送hello
    ws.onopen=function (){
        ws.send("hello")
    }
    //监听数据ws://localhost:8080/myWs
    ws.onmessage=function (message){
        console.log(message.data)
    }
</script>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1667103.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

字节码基础

基本概念 java中的字节码&#xff0c;英文bytecode。是java代码编译后的中间代码格式。JVM需要读取并解析字节码才能执行相应的任务。java字节码是JVM的指令集。JVM加载字节码格式的class文件。校验之后通过JIT编译器转换成本机机器代码执行。 java字节码简介 1、java byteco…

MySQL 身份认证漏洞 CVE-2012-2122

漏洞影响版本 MariaDB versions from 5.1.62, 5.2.12, 5.3.6, 5.5.23 are not.MySQL versions from 5.1.63, 5.5.24, 5.6.6 are not.演示 开启靶场 进入漏洞目录 cd /root/vulhub/mysql/CVE-2012-2122开启漏洞靶场 docker-compose up -d攻击 直接 运行 这个命令 for i i…

基于SSM+Vue的物流管理系统

运行截图 获取方式 Gitee仓库

Linux开发--Linux内核开发移植

Linux内核开发移植 Linux内核版本变迁及其获得 Linux是最受欢迎的自由电脑操作系统内核&#xff0c; 是一个用C语言写成&#xff0c; 并且符合POSIX标准的类Unix操作系统 Linux是由芬兰黑客Linus Torvalds开发的&#xff0c; 目的是尝试在英特尔x86架构上提供自由免费的类Un…

旅游推荐管理系统(小组项目)

文章目录 前言 一、项目介绍 1. 项目目的 2. 项目意义 2.1 提升旅游体验 2.2 促进旅游业发展 2.3 数据积累与分析 2.4 提升服务品质 2.5 优化资源配置 二、项目结构 1. 主要使用的技术 1.1 若依&#xff08;Ruoyi&#xff09;框架 1.2 Vue.js框架 1.3 Ajax 1.4 …

RS2227XN功能和参数介绍及PDF资料

RS2227XN是一款模拟开关/多路复用器 品牌: RUNIC(润石) 封装: MSOP-10 描述: USB2.0高速模拟开关 开关电路: 双刀双掷(DPDT) 通道数: 2 工作电压: 1.8V~5.5V 导通电阻(RonVCC): 10Ω 功能&#xff1a;模拟开关/多路复用器 USB2.0高速模拟开关 工作电压范围&#xff1a;1.8V ~ 5…

leetcode刷题指南

本文我将分享给大家一套我自己使用良久并觉得非常高效的 学习论&#xff0c;它可以运用到 Leetcode 上的刷题&#xff0c;也可以 generalize 到生活中涉及到学习以及记忆的方方面面。当然&#xff0c;本文将以 Leetcode 刷题为 case study 去进行讲解。 更具体一点, 我会教大家…

WEB后端复习——JSP、EL、JSTL

JSP:Java Serve Pages(Java服务器页面) 运行在服务器的脚本、在静态网页HTML代码中嵌入java 优势特点 1.被编译后可以多次直接运行&#xff0c;代码执行效率高&#xff08;一次加载、多次可用&#xff09; 2.动态代码封装&#xff0c;组件可重用性高&#xff08;JavaBean EJ…

Linux安装配置CGAL,OpenCV和Gurobi记录

安装Qt&#xff0c;查看当前的Qt版本&#xff0c;需要至少满足v5.12 qmake -v安装CGAL&#xff0c;The Computational Geometry Algorithms Library (cgal.org) CGAL v5.6.1&#xff1a;https://github.com/CGAL/cgal/releases/download/v5.6.1/CGAL-5.6.1.tar.xz 确保C编译…

图鸟UI vue3:基于Vue3和UniApp的酷炫简洁UI框架

引言 随着前端技术的不断发展&#xff0c;开发效率和用户体验成为了前端开发中的两大关键因素。为了提高开发效率和提供更好的用户体验&#xff0c;各种UI框架应运而生。其中&#xff0c;TuniaoUI作为一款基于Vue3和UniApp开发的UI组件库&#xff0c;以其酷炫简洁的设计和丰富…

厉害了!12秒将百万数据通过EasyExcel导入MySQL数据库中

一、写在开头 我们在上一篇文章中提到了通过EasyExcel处理Mysql百万数据的导入功能&#xff08;一键看原文&#xff09;&#xff0c;当时我们经过测试数据的反复测验&#xff0c;100万条放在excel中的数据&#xff0c;4个字段的情况下&#xff0c;导入数据库&#xff0c;平均耗…

【计算机毕业设计】基于微信小程序的校园综合服务

随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;校园综合服务被用户普遍使用&#xff0c;为方便用户能够可以随时…

李飞飞首次创业!

B站&#xff1a;啥都会一点的研究生公众号&#xff1a;啥都会一点的研究生 最近AI又有啥进展&#xff1f;一起看看吧~ 中国独角兽企业已达369家&#xff0c;六成以上与AI、芯片等硬科技赛道有关 2024中关村论坛“全球独角兽企业大会”上发布全新《中国独角兽企业发展报告&am…

win10建立共享文件夹和ipad共享文件

win10端设置 查看自己的局域网IP 在任意地方新建一个文件夹 打开文件夹的属性,点到共享的地方 点击高级共享 然后点击应用,确认 再回到之前哪个地方,点击共享 把Everyone的权限改为读取/写入 最后点击共享就欧克了 失败的可能原因 ipad端设置 然后回出现一个要输入用户名和…

【Python项目】基于大数据的【电影市场预测分析】

技术简介&#xff1a;使用Python技术、B/S架构、MYSQL数据库等实现。 系统简介&#xff1a;系统都需要简单的安全登陆检查&#xff0c;在登陆成功之后要进行在映电影的分析、票房分析、电影数据等功能相关性的数据统计&#xff0c;为了使用方便这些统计型的数据使用图表来进行表…

微信公众号接入chatGPT自动回复(2)

微信公众平台 配置自动回复的服务器 application.properties中的配置 验证服务器接口配置 其实就两个接口(相同的url地址,只不过请求方式不一样) 1.验证接口(get请求) 2.自动回复接口(post请求) 完整代码 这个地址就是上面URL配置的地址 如果使用Nginx的话自动配置 将该代…

根据蛋白质序列,计算其分子量(molecular weight),在线工具,原理和python代码

蛋白质分子量 蛋白质是由许多氨基酸残基通过肽键&#xff08;一个氨基酸的 α-羧基与另一个氨基酸的 α-氨基脱水缩合形成的化学键&#xff09;连接而成。蛋白质的分子量&#xff08;molecular weight&#xff09;为各个氨基酸的分子量之和&#xff0c;是蛋白质的重要理化参数…

sqli-labs靶场第十四关

目录 1&#xff1a;分析 找闭合符&#xff1a; 2&#xff1a;开始注入 报错注入&#xff1a; 注入数据库名&#xff1a; 注入表名&#xff1a; 注入列名&#xff1a; 注入具体值&#xff1a; 1&#xff1a;分析 经过我们的实验发现当我们输入的密码后面存在双引号时会报…

[数据结构]动画详解单链表

&#x1f496;&#x1f496;&#x1f496;欢迎来到我的博客&#xff0c;我是anmory&#x1f496;&#x1f496;&#x1f496; 又和大家见面了 欢迎来到动画详解数据结构系列 用通俗易懂的动画的动画使数据结构可视化 先来自我推荐一波 个人网站欢迎访问以及捐款 推荐阅读 如何低…

数据分析的统计推断

数据分析的统计推断 前言一、提出问题二、统计归纳方法三、统计推断四、统计推断步骤如何进行统计推断统计推断的基本问题点估计区间估计总体方差已知总体方差未知 假设检验假设检验的假设显著性水平 五、检验统计量常见的检验统计量 六、检验方法七、拒绝域八、假设检验步骤九…