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配置一樣
運行項目結果: