spring boot+tyrus实现websocket通信

262 阅读2分钟

新手小白学java的第不知道多少天

<dependency>
  <groupId>org.glassfish.tyrus</groupId>
  <artifactId>tyrus-server</artifactId>
  <version>1.17</version>
</dependency>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

这是项目依赖 在此遇到了两个大坑:

  • 前端访问socket 404
  • socket中无法自动装配

基本用法

创建socket配置类

@Configuration
public class WebsocketConfig {
    @Bean
    public ServerEndpointExporter ServerEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

在此我踩了一个坑,我一直以为是返回的是操作socket的那个类,这个是固定写法,直接cv即可

然后使用socket

@Component
@ServerEndpoint("/websocket") //指定socket服务器路径
public class SocketController {
    @OnOpen
    public void onOpen(Session session) {
        //监听连接
        System.out.println("连接成功");
    }
    @OnMessage
    public void onMessage(Session session, String msg) {
        // 监听消息
    }

    @OnClose
    public void onClose(Session session) {
        //监听关闭
        System.out.println("连接关闭");
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        //监听发生错误
        System.out.println("发生错误");
    }
}

Component不能少
ServerEndpoint指定服务器路径,前端请求就是ws://127.0.0.1:80/websocket
通过session.getBasicRemote().sendObject();发送消息

基本到这就可以跑起来了 如果要使用Service或者Mapper

// 因为websocket是多实例的,每创建一个连接就会创建一个bean,而spring中,如果没有特别声明,创建的都是单实例
// 在程序启动时,容器就对此bean进行了初始化,但是之后的连接时创建的对象,是没有任何bean注入操作的

所以在socketController中做如下操作

public static ApplicationContext applicationContext; //这个是sb的启动类那返回的
public static void setApplicationContext(ApplicationContext applicationContext) {
    SocketController.applicationContext = applicationContext; //在启动类将applicationcontext传入即可
}
// 启动类
ConfigurableApplicationContext run = SpringApplication.run(LianxiApplication.class, args);
SocketController.setApplicationContext(run);
//socketController
//有要使用的bean直接getBean(bean.class)获取即可使用
RecommendService recommendService = SocketController.applicationContext.getBean(RecommendService.class); 

我还需要存储数据库,当时报错

javax.websocket.EncodeException: No encoder specified for object of class [class com.example.lianxi.entity.Recommend] java.lang.RuntimeException:   
javax.websocket.EncodeException: No encoder specified for object of class [class com.example.lianxi.entity.Recommend]

这是因为缺少消息编码器

public class SockenEncoder implements Encoder.Text<Recommend> {//消息编码器类
    @Override
    public String encode(Recommend recommend) throws EncodeException { //将对象编码为字符串
        return JSON.toJSONString(recommend); //返回对象的时候将通过这个方法进行序列化
    }

    @Override
    public void init(EndpointConfig endpointConfig) { //初始化编码器

    }

    @Override
    public void destroy() { 、、销毁编码器

    }
}

要对socketcontroller进行修改 @ServerEndpoint("/websocket")改为
@ServerEndpoint(value = "/websocket", encoders = {SockenEncoder.class}) 这个的意思是value指定socket路径,encoders指定编码器的文件
现在就可以愉快的玩耍了
如果需要根据不同的id发送不同的内容,可以

private static final Map<String, Session> socketMap = new HashMap<>();
put("key",session) //这样就可以了,根据key获取session,然后通过session即可发送消息

必须使用static,否则每次请求都会重置,想了好久才解决。。。