Spring實現WebSocket通信


WebSocket是兩個應用之間全雙工的通信通道。WebSocket最常見的應用場景是實現服務器和基於瀏覽器的應用之間的通信。

瀏覽器中的javascript客戶端開啟一個到服務器的連接,服務器通過這個連接發送更新給瀏覽器。相比輪詢服務端以查找更新的

方案,這種技術更加高效。

下面將通過兩種方式(XML配置和Java類配置)實現WebSocket的簡單應用。

需要說明的是,由於本人瀏覽器無法支持WebSocket(這也是WebSocket令人遺憾的地方),所以使用WebSocket的備用方案

SockJS。SockJS會優先選用WebSocket,但是如果WebSocket不可用的話,它將會從其他方案中挑選最優方案。

不論哪種方案,首先要在maven項目中添加相關依賴:

<!-- WebSocket依賴 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-websocket</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>
<!-- 處理json數據 -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.8</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.8</version>
    </dependency>

注意,后兩個依賴不能忘記,不然會在通信時出錯

一、通過XML配置

在之前的項目中,我們首先創建example.websocket包,用於存放我們定義的處理器類。在該包中創建我們的

WebSocket處理器類MyHandler:

package example.websocket;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

/**
 * webSocket處理器
 */
public class MyHandler extends TextWebSocketHandler {
    private static final Logger log = LoggerFactory.getLogger(MyHandler.class);

    /**
     * 處理接收的信息行為
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        log.info("Received message: " + message.getPayload());
        session.sendMessage(new TextMessage("Server has received your message"));
    }

    /**
     * 處理建立連接后的事件
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        log.info("Connection established");
    }

    /**
     * 處理連接關閉事件
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        log.info("Connection closed. Status: " + status);
    }
}

接下來我們要在DispatcherServlet中配置我們的WebSocket:

<websocket:handlers>
        <websocket:mapping path="/myHandler" handler="myHandler"/>
        <websocket:sockjs/>
    </websocket:handlers>
    <bean id="myHandler" class="example.websocket.MyHandler"/>

注意,這段代碼應放入dispatcher-servlet.xml中,其中<websocket:sockjs/>標簽配置了SockJS

接下來我們創建一個新的Controller類用於加載一個獨立的視圖:

package example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping(value = "websocket")
public class CommunicationController {

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView webSocketView() {
        ModelAndView modelAndView = new ModelAndView("webSocketClient");
        return modelAndView;
    }
}

下面我們來編寫一個簡易的前端代碼,創建webSocketClient.jsp文件,需要注意,在使用SockJS之前,需要引入相應的庫,

具體參見https://github.com/sockjs/sockjs-client,這里借用了其他博主的代碼https://blog.csdn.net/dadiyang/article/details/83715569

<%--
  Created by IntelliJ IDEA.
  User: asus1
  Date: 2019/1/24
  Time: 21:58
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>webSocket客戶端</title>
</head>
<body>
<h1>Welcome!</h1>
<ul id="ul">
</ul>
<script  type="text/javascript" src="${pageContext.request.contextPath}/statics/js/sockjs-1.0.0.min.js"></script>
<script>
    var url = '/myHandler';
    var sock = new SockJS(url);

    sock.onopen = function (ev) {
        console.log("opening");
        sayHey();
    };
    sock.onmessage = function (ev) {
        console.log(ev.data);
        var li = document.createElement("li");
        li.innerText = ev.data;
        document.getElementById("ul").appendChild(li);
        setTimeout(sayHey, 2000);
    };
    sock.onclose = function (ev) {
        console.log("closed");
    };
    function sayHey() {
        console.log("sending 'Hey guy!'");
        sock.send("Hey guy!");
    };
</script>
</body>
</html>

運行項目結果:

二、通過java類配置

完全依照其他博主的方法重新創建了一個項目,整個項目通過java類進行配置

參考資料:https://blog.csdn.net/dadiyang/article/details/83715569

     《Spring 實戰(第4版)》

下面直接粘代碼:

配置類:

RootConfig:

package com.example.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@ComponentScan(basePackages = {"com.example"},
    excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)
    })
public class RootConfig {
}

WebConfig:

package com.example.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

/**
 * WebMvcConfigurerAdapter在新版本中已被棄用
 * 可以通過實現WebMvcConfigurer或者拓展WebMvcConfigurerSupport
 * 替代WebMvcConfigurerAdapter的拓展
 */
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.example"})
public class WebConfig implements WebMvcConfigurer {

    /**
     * 配置jsp視圖解析器
     * @param registry
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/views/", ".jsp");
    }

    /**
     * 配置靜態資源的處理
     * @param configurer
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

WebSocketConfig:

package com.example.config;

import com.example.websocket.MyHandler;
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;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
        webSocketHandlerRegistry.addHandler(myHandler(), "/myHandler").withSockJS();
    }

    @Bean
    public MyHandler myHandler() {
        return new MyHandler();
    }
}

WebApp初始化類:

package com.example.webappinit;

import com.example.config.RootConfig;
import com.example.config.WebConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class wsWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] {RootConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] {WebConfig.class};
    }
}

其他代碼與XML配置一樣

運行項目結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM