詳解WebSocket+spring示例demo(已使用sockJs庫)
1、簡介
作為下一代的Web標準,HTML5擁有許多引人注目的新特性,如 Canvas、本地存儲、多媒體編程接口、WebSocket等等。這其中有“Web的 TCP”之稱的 WebSocket格外吸引開發(fā)人員的注意。WebSocket的出現(xiàn)使得瀏覽器提供對 Socket的支持成為可能,從而在瀏覽器和服務(wù)器之間提供了一個基于TCP連接的雙向通道。Web開發(fā)人員可以非常方便地使用WebSocket構(gòu)建實時 web 應(yīng)用,開發(fā)人員的手中從此又多了一柄神兵利器。
Web 應(yīng)用的信息交互過程通常是客戶端通過瀏覽器發(fā)出一個請求,服務(wù)器端接收和審核完請求后進行處理并返回結(jié)果給客戶端,然后客戶端瀏覽器將信息呈現(xiàn)出來,這種機制對于信息變化不是特別頻繁的應(yīng)用尚能相安無事,但是對于那些實時要求比較高的應(yīng)用來說,比如說在線游戲、在線證券、設(shè)備監(jiān)控、新聞在線播報、RSS訂閱推送等等,當(dāng)客戶端瀏覽器準備呈現(xiàn)這些信息的時候,這些信息在服務(wù)器端可能已經(jīng)過時了。
所以保持客戶端和服務(wù)器端的信息同步是實時 Web應(yīng)用的關(guān)鍵要素,對 Web開發(fā)人員來說也是一個難題。在 WebSocket規(guī)范出來之前,開發(fā)人員想實現(xiàn)這些實時的Web應(yīng)用,不得不采用一些折衷的方案,其中最常用的就是輪詢(Polling)和 Comet 技術(shù),而Comet技術(shù)實際上是輪詢技術(shù)的改進,又可細分為兩種實現(xiàn)方式,一種是長輪詢機制,一種稱為流技術(shù)。
Html5 WebSocket 設(shè)計出來的目的就是要取代輪詢和 Comet技術(shù),使客戶端瀏覽器具備像 C/S架構(gòu)下桌面系統(tǒng)的實時通訊能力。瀏覽器通過JavaScript向服務(wù)器發(fā)出建立 WebSocket連接的請求,連接建立以后,客戶端和服務(wù)器端就可以通過 TCP連接直接交換數(shù)據(jù)。因為 WebSocket連接本質(zhì)上就是一個TCP連接,所以在數(shù)據(jù)傳輸?shù)姆€(wěn)定性和數(shù)據(jù)傳輸量的大小方面,和輪詢以及Comet技術(shù)比較,具有很大的性能優(yōu)勢。
但是鑒于web socket 對瀏覽器要求比較高,為了解決這個問題,推出了sockJS,SockJS是一個JavaScript庫,提供跨瀏覽器javascript的API,創(chuàng)建了一個低延遲、全雙工的瀏覽器和web服務(wù)器之間通信通道。
2、相關(guān)環(huán)境要求
Spring4.0.6(要選擇4.0+),tomcat7.0.55版本,JDK1.7。
3、具體代碼
(以下代碼親測可用!)
(1)web.xml:
<?xmlversionxmlversion="1.0"encoding="UTF-8"?> <web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"> <description>用來測試WebSocket基礎(chǔ)上推送的功能</description> <distributable/> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <async-supported>true</async-supported> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Spring 刷新Introspector防止內(nèi)存泄露 --> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <session-config> <session-timeout> 30 </session-timeout> </session-config> <welcome-file-list> <welcome-file>testSocket.jsp</welcome-file> </welcome-file-list> </web-app>
(2) dispatcher-servlet.xml
<?xmlversionxmlversion="1.0"encoding="UTF-8"?>
<beans:beansxmlnsbeans:beansxmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<annotation-driven/>
<!-- 自動掃描的包名 -->
<context:component-scanbase-packagecontext:component-scanbase-package="zyy.sockjs.config"></context:component-scan>
</beans:beans>
(3)HandshakeInterceptor.java
package zyy.sockjs.config;
import java.util.Map;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
@Component
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
System.out.println("Before Handshake");
return super.beforeHandshake(request,response,wsHandler,attributes);
}
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) {
System.out.println("After Handshake");
super.afterHandshake(request,response,wsHandler,ex);
}
}
(4)InfoSocketEndPoint.Java
package zyy.sockjs.config;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
@Component
public class InfoSocketEndPoint extends TextWebSocketHandler {
public InfoSocketEndPoint() {
}
@Override
protected void handleTextMessage(WebSocketSession session,
TextMessage message) throws Exception {
super.handleTextMessage(session, message);
TextMessage returnMessage = new TextMessage(message.getPayload()
+ " received at server");
session.sendMessage(returnMessage);
}
}
(5)SystemWebSocketHandler.java
package zyy.sockjs.config;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
/**
*
* @author dayu
*/
@Component
public class SystemWebSocketHandler implements WebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("connect to the websocket success......");
session.sendMessage(new TextMessage("Server:connected OK!"));
}
@Override
public void handleMessage(WebSocketSession wss, WebSocketMessage<?> wsm) throws Exception {
TextMessage returnMessage = new TextMessage(wsm.getPayload()
+ " received at server");
wss.sendMessage(returnMessage);
}
@Override
public void handleTransportError(WebSocketSession wss, Throwable thrwbl) throws Exception {
if(wss.isOpen()){
wss.close();
}
System.out.println("websocket connection closed......");
}
@Override
public void afterConnectionClosed(WebSocketSession wss, CloseStatus cs) throws Exception {
System.out.println("websocket connection closed......");
}
@Override
public boolean supportsPartialMessages() {
return false;
}
}
(6)WebSocketConfig.java
package zyy.sockjs.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.WebSocketHandler;
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
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements
WebSocketConfigurer {
public WebSocketConfig() {
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(systemWebSocketHandler(), "/websck").addInterceptors(new HandshakeInterceptor());
System.out.println("registed!");
registry.addHandler(systemWebSocketHandler(), "/sockjs/websck/info").addInterceptors(new HandshakeInterceptor())
.withSockJS();
}
@Bean
public WebSocketHandler systemWebSocketHandler() {
return new SystemWebSocketHandler();
}
}
(7)testSocket.jsp
<%@ page language="java"contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE htmlPUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type"content="text/html; charset=ISO-8859-1">
<title>WebSocket/SockJS Echo Sample (Adapted from Tomcat's echo sample)</title>
<style type="text/css">
#connect-container {
float: left;
width: 400px
}
#connect-container div {
padding: 5px;
}
#console-container {
float: left;
margin-left: 15px;
width: 400px;
}
#console {
border:1px solid #CCCCCC;
border-right-color:#33333333;
border-bottom-color:#999999;
height: 170px;
overflow-y: scroll;
padding: 5px;
width: 100%;
}
#console p {
padding: 0;
margin: 0;
}
</style>
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script type="text/javascript">
var ws = null;
var url = null;
var transports = [];
function setConnected(connected) {
document.getElementById('connect').disabled = connected;
document.getElementById('disconnect').disabled = !connected;
document.getElementById('echo').disabled = !connected;
}
function connect() {
if (!url) {
log('Select whether to use W3C WebSocket or SockJS');
return;
}
//ws = (url.indexOf('sockjs') != -1) ?new SockJS(url, undefined, {protocols_whitelist: transports}) : new WebSocket(url);
if ('WebSocket'in window) {
ws= new WebSocket("ws://localhost:8080/SpringSocketJs/websck");
}else {
ws = new SockJS("http://localhost:8080/SpringSocketJs/sockjs/websck/info");
}
//websocket = new SockJS("http://localhost:8084/SpringWebSocketPush/sockjs/websck");
ws.onopen = function () {
setConnected(true);
//log('Info: connection opened.');
};
ws.onmessage = function (event) {
log('Received: ' + event.data);
};
ws.onclose = function (event) {
setConnected(false);
log('Info: connection closed.');
log(event);
};
}
function disconnect() {
if (ws != null) {
ws.close();
ws = null;
}
setConnected(false);
}
function echo() {
if (ws != null) {
var message = document.getElementById('message').value;
log('Sent: ' + message);
ws.send(message);
} else {
alert('connection not established, please connect.');
}
}
function updateUrl(urlPath) {
if (urlPath.indexOf('sockjs') != -1) {
url = urlPath;
document.getElementById('sockJsTransportSelect').style.visibility ='visible';
}
else {
if (window.location.protocol =='http:') {
url = 'ws://' + window.location.host + urlPath;
} else {
url = 'wss://' + window.location.host + urlPath;
}
document.getElementById('sockJsTransportSelect').style.visibility ='hidden';
}
}
function updateTransport(transport) {
transports = (transport == 'all') ? [] : [transport];
}
function log(message) {
var console = document.getElementById('console');
var p = document.createElement('p');
p.style.wordWrap = 'break-word';
p.appendChild(document.createTextNode(message));
console.appendChild(p);
while (console.childNodes.length > 25) {
console.removeChild(console.firstChild);
}
console.scrollTop = console.scrollHeight;
}
</script>
</head>
<body>
<noscript><h2 style="color:#ff0000">Seems your browser doesn't supportJavascript!Websockets
rely on Javascript being enabled. Please enable
Javascript and reload this page!</h2></noscript>
<div>
<div id="connect-container">
<input id="radio1"type="radio"name="group1"onclick="updateUrl('/SpringSocketJs/websocket');">
<label for="radio1">W3C WebSocket</label>
<br>
<input id="radio2"type="radio"name="group1"onclick="updateUrl('/SpringSocketJs/sockjs/websocket');">
<label for="radio2">SockJS</label>
<div id="sockJsTransportSelect" style="visibility:hidden;">
SockJS transport:
<select onchange="updateTransport(this.value)">
<option value="all">all</option>
<option value="websocket">websocket</option>
<option value="xhr-polling">xhr-polling</option>
<option value="jsonp-polling">jsonp-polling</option>
<option value="xhr-streaming">xhr-streaming</option>
<option value="iframe-eventsource">iframe-eventsource</option>
<option value="iframe-htmlfile">iframe-htmlfile</option>
</select>
</div>
<div>
<button id="connect"onclick="connect();">Connect</button>
<button id="disconnect"disabled="disabled"onclick="disconnect();">Disconnect</button>
</div>
<div>
<textarea id="message"style="width:350px">Here is a message!</textarea>
</div>
<div>
<button id="echo"onclick="echo();"disabled="disabled">Echo message</button>
</div>
</div>
<div id="console-container">
<div id="console"></div>
</div>
</div>
</body>
</html>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
解讀@RequestBody與post請求的關(guān)系
這篇文章主要介紹了解讀@RequestBody與post請求的關(guān)系,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12
java 之JNA中的Memory和Pointer的使用方法
這篇文章主要介紹了java 之JNA中的Memory和Pointer的使用方法,文章基于Java的相關(guān)自來哦展開對Pointer和Memory的使用介紹,需要的小伙伴可以參考一下2022-04-04
Java經(jīng)典排序算法之歸并排序?qū)崿F(xiàn)代碼
這篇文章主要介紹了Java經(jīng)典排序算法之歸并排序?qū)崿F(xiàn)代碼,歸并排序是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法的一個非常典型的應(yīng)用,將已有序的子序列合并,得到完全有序的序列,需要的朋友可以參考下2023-10-10
詳解java如何實現(xiàn)帶RequestBody傳Json參數(shù)的GET請求
在調(diào)試Fate平臺時,遇到了一個奇葩的接口類型,該接口為Get方式,入?yún)⑹且粋€json類型在body中傳遞,使用body中傳參的話為什么不用POST請求而使用了GET請求,下面我們就來深入研究一下2024-02-02

