SpringBoot使用WebSocket

WebSocket 介绍

WebSocket 是一种建立在TCP之上的协议,主要用于解决服务器和客户端双向通话问题,具体可以参考 阮一峰WebSocket教程

Java Web项目使用WebSocket

JSR356 中对Java WebSocket API 有详细的规定,包含客户端API和服务端API,在使用java编写客户端时,利用注解是比较方便的方式,在类上添加@ClientEndpoint, 在不同的方法上添加@OnOpen @OnClose @OnError @OnMessage来处理不同的事件。

使用JAVA更多应用场景是提供WebSocket服务,同样也是通过注解的方式可以快速实现,在类上添加@ServerEndpoint,如

@ServerEndpoint("/game/{gameType}")
public class GameServer {

  @OnOpen
  public open () {...}
  
  @OnClose
  public close() {...}

  @OnMessage
  public message() {...}

  @OnError
  public error() {...}
}

通过上述的编码,可以获得一个地址类似 ws[s]://ip:port/game/type1 的WebSocket服务,要想获取gameType的值,可以使用@PathParam 注解

@OnMessage
public message(@PathParam("gameType") String gameType) {...}

Spring 中使用WebSocket

Java Web 最常用的框架自然是Spring莫属,在Spring中可以直接使用Java WebSocket API来提供服务,如果使用内置的web容器,需要做的仅仅是需要在配置文件中添加

    /**
     * The bean shown in the preceding example registers any @ServerEndpoint
     * annotated beans with the underlying WebSocket container. When deployed to a
     * standalone servlet container, this role is performed by a servlet container
     * initializer, and the ServerEndpointExporter bean is not required.
     * 
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

Spring 对WebSocket 也提供了一定的封装支持,可以参考Spring 的官网说明, 其实也比较简单,下面是我参考官网写的一段代码

package com.iflytek.research.storage.config;

import javax.annotation.Resource;

import org.springframework.context.annotation.Bean;
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 org.springframework.web.socket.server.standard.ServerEndpointExporter;

import com.iflytek.research.storage.repository.FileObjectRepository;
import com.iflytek.research.storage.repository.UserRepository;
import com.iflytek.research.storage.websocket.SearchHandler;

/**
 * 开启WebSocket支持
 * 参考:https://docs.spring.io/spring/docs/5.1.2.RELEASE/spring-framework-reference/web.html#websocket
 * 
 * @author ljgeng
 */
@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
    
    @Resource
    FileObjectRepository fileObjectRepository;
    
    @Resource
    UserRepository userRepository;
    
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new SearchHandler(fileObjectRepository,userRepository), "/api/search/**/").setAllowedOrigins("*");
    }
    

    /**
     * The bean shown in the preceding example registers any @ServerEndpoint
     * annotated beans with the underlying WebSocket container. When deployed to a
     * standalone servlet container, this role is performed by a servlet container
     * initializer, and the ServerEndpointExporter bean is not required.
     * 
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
    
}

Spring Security 和 WebSocket

我的项目是使用SpringBoot 搭建的,同时引入了Spring Security 来做安全管理,在发布WebSocket服务并不用过多处理,在上述的SearchHandler中,它继承了TextWebSocketHandler,在重新实现handleTextMessage方式时,其中有一个参数WebSocketSession就包含了用户信息

public class SearchHandler extends TextWebSocketHandler {
    
    private final FileObjectRepository fileObjectRepository;
    private final UserRepository userRepository;
    
    public SearchHandler(FileObjectRepository fileObjectRepository,UserRepository userRepository) {
        this.fileObjectRepository = fileObjectRepository;
        this.userRepository = userRepository;
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        // 当前用户账号
        Principal  principal = session.getPrincipal();
        String username = principal.getName();
        ...
    }
    ...
}

猜你喜欢

转载自www.cnblogs.com/ljgeng/p/9984101.html