springboot整合websocker启动失败

在工作的时候,准备使用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();
    }


 

 
 
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值