WebSocket 簡介
WebSocket 是 HTML5 一種新的協議。它實現了瀏覽器與服務器全雙工通信,能更好的節省服務器資源和帶寬並達到實時通訊,它建立在 TCP 之上,同 HTTP 一樣通過 TCP 來傳輸數據,但是它和 HTTP 最大不同是:
- WebSocket 是一種雙向通信協議,在建立連接後,WebSocket 服務器和 Browser/Client Agent 都能主動的向對方發送或接收數據,就像 Socket 一樣;
- WebSocket 需要類似 TCP 的客戶端和服務器端通過握手連接,連接成功後才能相互通信。
整合示例
本示例爲演示WebSocket的廣播式模式,即服務端有消息時,會將消息發送給所有連接了當前endpoint的 Browser/Client Agent
1. maven引入依賴包
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<boot.version>1.3.6.RELEASE</boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>${boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>${boot.version}</version>
</dependency>
</dependencies>
2. 編寫WebSocket的配置類
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
/**
* @author ZhangPengFei
* @Discription
* @Data 2017-3-7
* @Version 1.0.0
*/
@Configuration
//開啓對WebSocket的支持
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
/**
* 註冊一個STOMP協議的節點,並映射到指定的URL
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//註冊一個STOMP的endpoint,並指定使用SockJS協議
registry.addEndpoint("/endpointSocket").withSockJS();
}
/**
* 配置消息代理
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
//配置一個廣播式的消息代理
registry.enableSimpleBroker("/topic");
}
}
3. 瀏覽器向服務器端發送消息的實體封裝類
/**
* @author ZhangPengFei
* @Discription
* @Data 2017-3-7
* @Version 1.0.0
*/
public class SocketMessage {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
4. 服務器向瀏覽器響應數據的封裝實體類
/**
* @author ZhangPengFei
* @Discription
* @Data 2017-3-7
* @Version 1.0.0
*/
public class SocketResponse {
private String responseMessage;
public SocketResponse(String responseMessage) {
this.responseMessage = responseMessage;
}
public String getResponseMessage() {
return responseMessage;
}
}
5. 請求控制器
import com.os.china.entity.SocketMessage;
import com.os.china.entity.SocketResponse;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author ZhangPengFei
* @Discription
* @Data 2017-3-7
* @Version 1.0.0
*/
@Controller
public class WebSocketController {
private SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//當瀏覽器向服務器端發送STOMP請求時,通過@MessageMapping註解來映射/getServerTime地址
@MessageMapping(value = "/getServerTime")
//當服務端有消息時,會對訂閱了@SendTo中的路徑的客戶端發送消息
@SendTo(value = "/topic/getResponse")
public SocketResponse serverTime(SocketMessage message) throws InterruptedException {
return new SocketResponse(message.getMessage() + sf.format(new Date()));
}
}
6. 配置WebMvc視圖映射
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @author ZhangPengFei
* @Discription
* @Data 2017-3-7
* @Version 1.0.0
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{
/**
* MVC視圖控制器配置
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//添加一個請求映射地址爲/index,返回對應視圖頁面爲webSocket
registry.addViewController("/index").setViewName("/webSocket");
}
}
7. 腳本添加,將 stomp.min.js(STOMP協議的客戶端腳本),socketjs.min.js(SocketJS的客戶端腳本)和 jQuery腳本放在src/main/resources/static下
注:STOMP協議的客戶端連接詳細介紹,請移步至我的另外一篇文章,WebSocket子協議STOMP詳解 https://my.oschina.net/feinik/blog/853875
8. 在項目的src/main/resources/templates下新建webSocket.html頁面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>集成WebSocket示例</title>
</head>
<body>
<div>
<button id="connect" onclick="connect();">連接</button>
<button id="disconnect" onclick="disconnect();">斷開連接</button>
<button id="serverTimeId" onclick="getServerTime();">獲取服務器端時間</button>
<hr/>
<span id="showServerTime"></span>
</div>
<script type="text/javascript" src="sockjs.min.js"></script>
<script type="text/javascript" src="stomp.min.js"></script>
<script type="text/javascript" src="jquery-3.1.1.min.js"></script>
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script type="text/javascript">
var stompClient = null;
$(function(){
setConnect(false);
});
function setConnect(connected){
$("#connect").attr({disabled:connected});
$("#disconnect").attr({disabled:!connected});
}
function connect() {
var socket = new SockJS('/endpointSocket');
//創建STOMP客戶端連接,目標地址爲/endpointSocket的STOMP代理
stompClient = Stomp.over(socket);
//打印stomp輸出信息
stompClient.debug = function(str) {
console.log(str + "\n");
};
//建立連接
stompClient.connect({},function(frame) {
setConnect(true);
//連接成功後訂閱/topic/getResponse目標發送的消息,該地址在Controller中用@SendTo指定
stompClient.subscribe('/topic/getResponse', function(response) {
showResponse(JSON.parse(response.body).responseMessage);
});
});
}
function disconnect() {
if(stompClient != null) {
stompClient.disconnect();
}
setConnect(false);
}
function getServerTime() {
var message = "The server time is : ";
//發送消息到服務端,/getServerTime地址是由Controller中的@MessageMapping指定
stompClient.send("/getServerTime",{},JSON.stringify({'message':message}));
}
function showResponse(message){
var response = $("#showServerTime");
response.html(message);
}
</script>
</body>
</html>
9. 編寫SpringBoot的啓動類
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author ZhangPengFei
* @Discription
* @Data 2017-3-7
* @Version 1.0.0
*/
@SpringBootApplication
public class ApplicationTest {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(ApplicationTest.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
}
10. 啓動並測試,也可打開多個瀏覽器窗口連接到WebSocket服務端,在其中一個瀏覽器窗口中點擊獲取服務器時間,其他兩個也將接收到消息
好了,整合到此完結,具體代碼已上傳至GitHub https://github.com/AIFEINIK/SpringBoot-Learn/tree/master/spring-boot-websocket