springboot整合websocker启动失败

news2024/11/19 19:37:53

在工作的时候,准备使用websocker建立长连接来统计网站在线人数,但是在配置好所有东西后,发现springboot启动失败

 详细错误 

java.lang.IllegalStateException: Failed to register @ServerEndpoint class: class com.example.pipayshopapi.component.WebSocketServer
	at org.springframework.web.socket.server.standard.ServerEndpointExporter.registerEndpoint(ServerEndpointExporter.java:159) ~[spring-websocket-5.3.3.jar:5.3.3]
	at org.springframework.web.socket.server.standard.ServerEndpointExporter.registerEndpoints(ServerEndpointExporter.java:134) ~[spring-websocket-5.3.3.jar:5.3.3]
	at org.springframework.web.socket.server.standard.ServerEndpointExporter.afterSingletonsInstantiated(ServerEndpointExporter.java:112) ~[spring-websocket-5.3.3.jar:5.3.3]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:963) ~[spring-beans-5.3.3.jar:5.3.3]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:923) ~[spring-context-5.3.3.jar:5.3.3]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:588) ~[spring-context-5.3.3.jar:5.3.3]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.2.jar:2.4.2]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767) [spring-boot-2.4.2.jar:2.4.2]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-2.4.2.jar:2.4.2]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) [spring-boot-2.4.2.jar:2.4.2]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) [spring-boot-2.4.2.jar:2.4.2]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) [spring-boot-2.4.2.jar:2.4.2]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) [spring-boot-2.4.2.jar:2.4.2]
	at com.example.pipayshopapi.PipayshopApiApplication.main(PipayshopApiApplication.java:16) [classes/:na]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_382]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_382]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_382]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_382]
	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.4.2.jar:2.4.2]
Caused by: javax.websocket.DeploymentException: No payload parameter present on the method [onMessage] of class [com.example.pipayshopapi.component.WebSocketServer] that was annotated with OnMessage
	at org.apache.tomcat.websocket.pojo.PojoMethodMapping$MessageHandlerInfo.<init>(PojoMethodMapping.java:567) ~[tomcat-embed-websocket-9.0.41.jar:9.0.41]
	at org.apache.tomcat.websocket.pojo.PojoMethodMapping.<init>(PojoMethodMapping.java:139) ~[tomcat-embed-websocket-9.0.41.jar:9.0.41]
	at org.apache.tomcat.websocket.server.WsServerContainer.addEndpoint(WsServerContainer.java:154) ~[tomcat-embed-websocket-9.0.41.jar:9.0.41]
	at org.apache.tomcat.websocket.server.WsServerContainer.addEndpoint(WsServerContainer.java:278) ~[tomcat-embed-websocket-9.0.41.jar:9.0.41]
	at org.apache.tomcat.websocket.server.WsServerContainer.addEndpoint(WsServerContainer.java:228) ~[tomcat-embed-websocket-9.0.41.jar:9.0.41]
	at org.springframework.web.socket.server.standard.ServerEndpointExporter.registerEndpoint(ServerEndpointExporter.java:156) ~[spring-websocket-5.3.3.jar:5.3.3]
	... 18 common frames omitted

 在网上查了一番资料后,

1.有的说是aop导致的,

2.有的说是@ServerEndpoint 注解中配置路径必须以"/" 开头,

3.有的说的是SpringBoot内置Tomcat,使用ServerEndpointExporter扫描注册ServerEndpoint,而测试服务器的容器是Tomcat,使用自带jar包中的ServerApplicationConfig扫描注册ServerEndpoint,不同的容器使用不同的扫描机制
第一种,我没有配置aop所以不是这原因,pass。

第二种我有配置以"/"开头,pass

 

第三种,我没有试过,所以去试了一下:

在websockerconfig中加@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")注解

@Configuration
@ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev")
public class WebSocketConfig {

    /**
     * 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

 在websockerservce中加@ConditionalOnClass(value = WebSocketConfig.class)注解

@ServerEndpoint(value = "/dailyActive/{userId}")
@Component
@ConditionalOnClass(value = WebSocketConfig.class)
public class WebSocketServer {

    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    // 注入查看聊天列表的服务

    /**
     * 记录当前在线连接数
     */
    public static final Map<String, Session> dailyActiveCount = new ConcurrentHashMap<>();


    public static final String dailyActiveName="dailyActiveName";

//    @Resource
//    private StringRedisTemplate stringRedisTemplate;

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        log.error(userId+"----------------------------------------------进入");
        // 保存当前用户session
        dailyActiveCount.put(userId, session);
        // 存入redis中去
//        stringRedisTemplate.opsForValue().set(dailyActiveName,String.valueOf(dailyActiveCount.size()));
    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("userId") String userId) {
        log.error(userId+"----------------------------------------------关闭");
        // 移除当前用户session
        dailyActiveCount.remove(userId);
        // 存入redis中去
//        stringRedisTemplate.opsForValue().set(dailyActiveName,String.valueOf(dailyActiveCount.size()));
    }

    /**
     * 收到客户端消息后调用的方法
     * 后台收到客户端发送过来的消息
     * onMessage 是一个消息的中转站
     * 接受 浏览器端 socket.send 发送过来的 json数据
     */
    @OnMessage
    public void onMessage(Session session, @PathParam("userId") String userId) {



    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }


 

 
 
}

加了之后启动类,确实能启动了,我欣喜若狂,以为找到答案了 

但是在页面尝试连接websocker的时候,当场给我泼了一盆冷水

 

 在网上搜了一波:

有的说是server.servlet.context-path,可是我已经写上去了,pass。

 其他都没有用,最后我在走投无路之下,去垃圾桶找回我以前能运行websocker的项目,在两个对比之下,原来是在@OnMessage方法少了一个参数 ,我猜想可能这个方法需要接收三个参数

 顺序无所谓

 都是能启动的

连接成功 

 

 详细的websockerconfig和websockerservice代码

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

@Configuration
public class WebSocketConfig {

    /**
     * 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}
import com.example.pipayshopapi.config.WebSocketConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;


import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


 
 
/**
 * @author websocket服务
 */


@ServerEndpoint(value = "/dailyActive/{userId}")
@Component
public class WebSocketServer {

    private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
    // 注入查看聊天列表的服务

    /**
     * 记录当前在线连接数
     */
    public static final Map<String, Session> dailyActiveCount = new ConcurrentHashMap<>();


    public static final String dailyActiveName="dailyActiveName";

//    @Resource
//    private StringRedisTemplate stringRedisTemplate;

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        log.error(userId+"----------------------------------------------进入");
        // 保存当前用户session
        dailyActiveCount.put(userId, session);
        // 存入redis中去
//        stringRedisTemplate.opsForValue().set(dailyActiveName,String.valueOf(dailyActiveCount.size()));
    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session, @PathParam("userId") String userId) {
        log.error(userId+"----------------------------------------------关闭");
        // 移除当前用户session
        dailyActiveCount.remove(userId);
        // 存入redis中去
//        stringRedisTemplate.opsForValue().set(dailyActiveName,String.valueOf(dailyActiveCount.size()));
    }

    /**
     * 收到客户端消息后调用的方法
     * 后台收到客户端发送过来的消息
     * onMessage 是一个消息的中转站
     * 接受 浏览器端 socket.send 发送过来的 json数据
     */
    @OnMessage
    public void onMessage(Session session, String message,@PathParam("userId") String userId) {



    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }


 

 
 
}

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

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

相关文章

【算法题解】54. 树的冗余连接

这是一道 中等难度 的题 https://leetcode.cn/problems/redundant-connection/ 题目 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n n n 个节点 (节点值 1 &#xff5e; n 1&#xff5e;n 1&#xff5e;n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 …

Python可视化在量化交易中的应用(11)_Seaborn折线图

举个栗子&#xff0c;用seaborn绘制折线图。 Seaborn中折线图的绘制方法 在seaborn中&#xff0c;我们一般使用sns作为seaborn模块的别名&#xff0c;因此&#xff0c;在下文中&#xff0c;均以sns指代seaborn模块。 seaborn中绘制折线图使用的是sns.plot()函数&#xff1a; …

【算法学习】两数之和II - 输入有序数组

题目描述 原题链接 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] &#xff0c;则 1 < index1 < …

JavaScript中的作用域(scope)是什么?以及有哪些类型的作用域?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 作用域&#xff08;Scope&#xff09;是什么&#xff1f;1. 全局作用域&#xff08;Global Scope&#xff09;2. 局部作用域&#xff08;Local Scope&#xff09;3. 块级作用域&#xff08;Block Scope&#xff09; ⭐ 写在最后 ⭐ 专栏简…

MPLAB X IDE 中的查找方式

1.第一种选择到变量&#xff0c;然后按ctrlf&#xff0c;这种方式只能在单个文件中查找&#xff1b; 2.第二种&#xff0c;按ctrlshiftf&#xff0c;前提必须在英文模式下&#xff0c; 对于普通用户来说&#xff0c;只需要知道Containing Text是搜索对象&#xff1b;最下面的F…

stm32红绿灯源代码示例(附带Proteus电路图)

本代码不能直接用于红路灯&#xff0c;只是提供一个思路 #include "main.h" #include "gpio.h" void SystemClock_Config(void); void MX_GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStruct {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOB_CLK_ENAB…

JavaScript中的变量声明方式有哪些?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 变量声明方式var 声明&#xff08;ES5及以前&#xff09;let 声明&#xff08;ES6以后&#xff09;const 声明&#xff08;ES6以后&#xff09; ⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者…

【算法学习】平方数之和

title: 【力扣】633.平方数之和 cover: ‘https://storage.bummon.com/image/202308171051399.png’ tags: 算法LeetCode双指针法二分查找法 categories:算法笔记 abbrlink: 2911343079 date: 2023-08-17 10:49:52 mathjax: true 【力扣】633.平方数之和 题目 原题链接 给定…

Vue 2 计算属性与侦听器

计算属性 vs 方法 vs 侦听器 计算属性的出现是为了解决模板内表达式太过复杂而变得难以维护。 假设我们知道长和宽&#xff0c;要计算一个矩形的面积&#xff0c;如果没有计算属性&#xff0c;我们可能像下面这样处理&#xff1a; <div id"app"><input t…

functools.wrap的使用

一、介绍 functools.wraps 是 Python 标准库中的一个函数&#xff0c;用于帮助创建装饰器时保留被装饰函数的元数据&#xff08;如函数名、文档字符串等&#xff09;。在使用装饰器时&#xff0c;如果不使用 functools.wraps&#xff0c;则被装饰函数的一些元数据可能会丢失或…

ubuntu系统快捷键

前言&#xff1a;可以在设置—>设备—>键盘中查看键盘快捷键 打开活动搜索界面 Super键 想要打开一个应用程序&#xff1f;按下 Super 键然后搜索应用程序。如果搜索的应用程序未安装&#xff0c;它会推荐来自应用中心的应用程序。 想要看看有哪些正在运行的程序&#xf…

【C++笔记】C++之类与对象(中)

【C笔记】C之类与对象&#xff08;中&#xff09; 1、类的构造函数1.1、构造函数的基本用法1.2、构造函数的7个特性 2、类的析构函数2.1、析构函数的基本用法2.2、析构函数的6个特性 3、类的拷贝构造函数3.1、拷贝构造的基本用法3.2、拷贝构造的“无限套娃”陷阱3.3、深拷贝与浅…

汽车领域专业术语

1. DMS/OMS/RMS/IMS DMS&#xff1a;即Driver Monitoring System&#xff0c;监测对象为Driver&#xff08;驾驶员&#xff09;。DMS三大核心&#xff1a; OMS&#xff1a;即Occupancy Monitoring System&#xff0c;监测对象为乘客。 RMS&#xff1a;后排盲区检测系统 IMS&…

动手学深度学习--基础知识上篇

&#x1f388;动手学deep learning ☁️本专栏会定期更新关于动手学深度学习的每章知识点的讲解&#xff0c;题目答案 &#x1f47b;如果喜欢&#xff0c;欢迎点赞&#xff0c;收藏 动手学深度学习-预备知识篇 线性代数篇 1-3题讲解 证明一个矩阵 A \mathbf{A} A的转置的转置…

C#程序配置读写例子 - 开源研究系列文章

今天讲讲关于C#的配置文件读写的例子。 对于应用程序的配置文件&#xff0c;以前都是用的ini文件进行读写的&#xff0c;这个与现在的json类似&#xff0c;都是键值对应的&#xff0c;这次介绍的是基于XML的序列化和反序列化的读写例子。对于ini文件&#xff0c;操作系统已经提…

Java课题笔记~ 整合第三方技术

1. 整合JUnit 问题导入 回忆一下Spring整合JUnit的步骤&#xff1f; 1.1 Spring整合JUnit&#xff08;复习&#xff09; 1.2 SpringBoot整合JUnit 【第一步】添加整合junit起步依赖(可以直接勾选) <dependency><groupId>org.springframework.boot</groupId…

什么是变量提升(hoisting)?它在JavaScript中是如何工作的?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 变量提升&#xff08;Hoisting&#xff09;⭐ 变量提升的示例&#xff1a;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&…

水果成篮(力扣)双指针滑动窗口 JAVA

你正在探访一家农场&#xff0c;农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示&#xff0c;其中 fruits[i] 是第 i 棵树上的水果 种类 。 你想要尽可能多地收集水果。然而&#xff0c;农场的主人设定了一些严格的规矩&#xff0c;你必须按照要求采摘水果&…

[管理与领导-27]:IT基层管理者 - 团队管理 - 育人 - 如何评估团队的能力?如何培养团队?

目录 一. 培养团队&#xff08;练兵&#xff09;为什么很重要 二. 如何评估团队的能力模型 三、培养人才 一. 培养团队&#xff08;练兵&#xff09;为什么很重要 培养团队是组织中的一项重要任务&#xff0c;以下是一些说明为什么培养团队是如此重要的原因&#xff1a; 养…

MAC QT开发攻略

文章目录 基础步骤安装QT、QTCreator安装CMakeNinja 安装Clion编译器在QTCreator中新建项目更改CMake生成器 导入Clion CMake生成文件 基础步骤 安装QT、QTCreator 安装CMake 由于clion需要使用cmake构建 Ninja Ninja下载 安装Clion编译器 Clion 2023.1.3 破解版安装教程…