Springboot实现websocket

Posted 诺浅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Springboot实现websocket相关的知识,希望对你有一定的参考价值。

Websocket

在前面的文章中我们讲到了websocket和传统的http有什么区别,以及websocket用来实现服务器推的优势,那么这篇文章就来说说,在Java中如果要实现一个websocket应该怎么实现,这里采用的是更加方便的Springboot的方式,如果项目中没有使用springboot框架,也是可以实现的,本文不涉及。

代码

服务端

1、先引入springboot-websocket的starter

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

2、定义一个WebSocketBean,用来保存组装的信息,这个Bean也可以自己添加其他的属性

@Getter
@Setter
public class WebSocketBean 
    private WebSocketSession webSocketSession;
    private int clientId;
    private String token;

3、连接或断开处理类

@Slf4j
public class MyWebsocketHandler extends AbstractWebSocketHandler 

    public static final Map<String, WebSocketBean> webSocketBeanMap;

    /**
     * 仅用用于标识客户端编号
     */
    private static final AtomicInteger clientIdMaker;

    static 
        webSocketBeanMap = new ConcurrentHashMap<>();
        clientIdMaker = new AtomicInteger(0);
    

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception 
        // 当WebSocket连接正式建立后,将该Session加入到Map中进行管理
        Map<String, Object> attributes = session.getAttributes();
        WebSocketBean webSocketBean = new WebSocketBean();
        webSocketBean.setWebSocketSession(session);
        webSocketBean.setClientId(clientIdMaker.getAndIncrement());
        webSocketBean.setToken(attributes.get("token").toString());
        webSocketBeanMap.put(session.getId(), webSocketBean);
    

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception 
        //当连接关闭后,从Map中移除session实例
        webSocketBeanMap.remove(session.getId());
    

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception 
        //传输过程中出现了错误
        if (session.isOpen()) 
            session.close();
        
        webSocketBeanMap.remove(session.getId());
    

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception 
        //处理接收到的消息
        log.info("Received message from client[ID:" + webSocketBeanMap.get(session.getId()).getClientId() +
                "]; Content is [" + message.getPayload() + "].");
        TextMessage textMessage = new TextMessage("Server has received your message.");
        session.sendMessage(textMessage);
    

4、把连接监控类配置进spring,用于程序启动时启动websocket

@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer 

    @Bean
    public MyWebSocketInterceptor webSocketInterceptor() 
        return new MyWebSocketInterceptor();
    

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

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) 
        webSocketHandlerRegistry
                .addHandler(new MyWebsocketHandler(), "/websocket")
                .addInterceptors(webSocketInterceptor());
    

5、可以做一个简单的鉴权

@Slf4j
public class MyWebSocketInterceptor extends HttpSessionHandshakeInterceptor 

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception 
        logger.info("[MyWebSocketInterceptor#BeforeHandshake] Request from " + request.getRemoteAddress().getHostString());
        if (request instanceof ServletServerHttpRequest) 
            ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
            String token = serverHttpRequest.getServletRequest().getParameter("token");

            //这里做一个简单的鉴权,只有符合条件的鉴权才能握手成功
            if ("123456".equals(token)) 
                // 保存认证用户
                attributes.put("token", token);
                return super.beforeHandshake(request, response, wsHandler, attributes);
             else 
                log.error("token错误。token:[]!", token, new ConsumablesCabinetException("token错误"));
                return false;
            
        
        return super.beforeHandshake(request, response, wsHandler, attributes);
    

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) 
        logger.info("[MyWebSocketInterceptor#afterHandshake] Request from " + request.getRemoteAddress().getHostString());
    

到此,websocket的服务端就完成了,启动工程,就会启动一个websocket服务,现在来实现客户端

客户端

客户端这里也是用java列出,实际上js等各种方式都可以实现
1、先引包

<dependency>
    <groupId>org.java-websocket</groupId>
    <artifactId>Java-WebSocket</artifactId>
    <version>1.5.1</version>
</dependency>

2、客户端连接断开监控类

public class MyWebSocketClient extends WebSocketClient 

    private Logger logger = LoggerFactory.getLogger(getClass());

    public MyWebSocketClient(URI serverUri) 
        super(serverUri);
    

    @Override
    public void onOpen(ServerHandshake serverHandshake) 
        logger.info("[MyWebSocketClient#onOpen]The WebSocket connection is open.");
    

    @Override
    public void onMessage(String s) 
        logger.info("[MyWebSocketClient#onMessage]The client has received the message from server." +
                "The Content is [" + s + "]");
    

    @Override
    public void onClose(int i, String s, boolean b) 
        logger.info("[MyWebSocketClient#onClose]The WebSocket connection is close.");
    

    @Override
    public void onError(Exception e) 
        logger.info("[MyWebSocketClient#onError]The WebSocket connection is error.");
    

3、启动类

public class MyWebSocketMain 

    private static final AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) 
        URI uri = URI.create("ws://localhost:8001/websocket?token=123456");
        MyWebSocketClient client = new MyWebSocketClient(uri);
        try 
            // 在连接成功之前会一直阻塞
            client.connectBlocking();

            Timer timer = new Timer();
            MyTimerTask timerTask = new MyTimerTask(client);
            timer.schedule(timerTask, 1000, 2000);
         catch (InterruptedException e) 
            e.printStackTrace();
        
    

    static class MyTimerTask extends TimerTask 

        private final MyWebSocketClient client;

        public MyTimerTask(MyWebSocketClient client) 
            this.client = client;
        

        @Override
        public void run() 
            client.send("Test message from client, the number is " + count.getAndIncrement());
        
    

运行服务端和客户端就可以看到服务器端不停的输出

Received message from client[ID:0]; Content is [Test message from client, the number is 0].

客户端不停的输出

The client has received the message from server.The Content is [Server has received your message.]

这样就说明成功了

以上是关于Springboot实现websocket的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot使用WebSocket实现服务端推送--集群实现

SpringBoot+Vue+Websocket 实现服务器端向客户端主动发送消息

springboot成神之——websocket发送和请求消息

Springboot实现websocket

Springboot实现websocket

Springboot实现websocket