Grade構建依賴
build.gradle檔案配置如下
buildscript {
ext {
springBootVersion = '1.5.9.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
group = 'com'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-redis')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.data:spring-data-redis')
compile group: 'com.alibaba', name: 'fastjson', version: '1.1.15'
runtime('mysql:mysql-connector-java')
compile("org.springframework.boot:spring-boot-starter-websocket")
compile("org.webjars:webjars-locator-core")
compile("org.webjars:sockjs-client:1.0.2")
compile("org.webjars:stomp-websocket:2.3.3")
testCompile('org.springframework.boot:spring-boot-starter-test')
}
複製程式碼
構建STOMP訊息服務、服務互動流程
建立一個資源表示
服務將接受包含STOMP訊息中名稱的訊息,該訊息的主體是JSON物件。如果給出的名稱是“Test”,那麼該訊息可能如下所示:
{
"username ": "Test"
}
複製程式碼
為了建模帶有名稱的訊息,可以使用username 屬性和相應的getUsername()方法建立一個普通的舊Java物件:
public class ReceiveBean {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "UserBeans{" +
"username='" + username + '\'' +
'}';
}
}
複製程式碼
在收到訊息並提取名稱後,服務將通過建立問候語並在客戶端訂閱的單獨佇列上釋出該問候語來處理它。問候語也將是一個JSON物件,可能看起來像這樣:
{
"content": "Hello, Test!"
}
複製程式碼
為了建模問候表示,可以新增另一個具有content屬性和相應getContent()方法的普通舊Java物件:
public class ServerStatus {
private String content;
public ServerStatus() {}
public ServerStatus (String content) {
this.content = content;
}
public String getContent () {
return content;
}
}
複製程式碼
Spring將使用Jackson JSON庫自動將型別例項編組
Greeting
為JSON。 接下來,建立一個控制器來接收serverStatus訊息併傳送問候訊息。 #####建立訊息處理控制器 在Spring使用STOMP訊息傳遞的方法中,STOMP訊息可以對映到到@Controller
類。例如,它ServerStatusController
被對映為處理訊息到目的地“/serverStatus”
@Controller
@EnableScheduling
public class ServerStatusController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
//當瀏覽器向服務端傳送請求時,通過@MessageMapping對映的地址,類似於@RequestMapping
@MessageMapping("/serverStatus")
@SendTo("/receive/message") //廣播所有使用者
//傳遞的引數會自動的被注入到userbean中
public ServerStatus serverStatus (ReceiveBean receiveBean) throws InterruptedException {
// 返回值被廣播給所有訂戶,如@SendTo註釋中所指定的"/receive/message" 。請注意,來自輸入訊息的名稱已被清理,因為在這種情況下,它將被回顯並重新呈現在客戶端的瀏覽器DOM中。
return new ServerStatus((int) (Math.random() * 10 + 50));
}
@Scheduled(fixedRate = 5000) //每個5秒提取一次
@SendTo("/receive/message") //廣播所有使用者
public Object sendAllMessage () {
// 發現訊息
simpMessagingTemplate.convertAndSend("/receive/message", new ServerStatus((int) (Math.random() * 10 + 50)));
return "callback";
}
}
複製程式碼
為STOMP訊息傳遞配置Spring
配置Spring以啟用WebSocket和STOMP訊息傳遞。
/**
* 為STOMP訊息傳遞配置Spring
* WebSocketConfig被註釋@Configuration為表明它是一個Spring配置類。
* @EnableWebSocketMessageBroker: @EnableWebSocketMessageBroker啟用WebSocket訊息處理,由訊息代理支援。
*/
@Configuration //@Configuration註解表明它是一個Spring配置類
@EnableWebSocketMessageBroker //通過@EnableWebSocketMessageBroker 註解啟用WebSocket訊息處理,由訊息代理支援。
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer{
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
/*
* 該registerStompEndpoints()方法註冊“/serverStatus”端點,
* 啟用SockJS後備選項,以便在WebSocket不可用時可以使用替代傳輸。
* SockJS客戶端將嘗試連線到“/serverStatus”並使用可用的最佳傳輸(websocket,xhr-streaming,xhr-polling等)。
* setAllowedOrigins: 允許跨域
*/
registry.addEndpoint("/serverStatus").setAllowedOrigins("*").withSockJS();
}
/**
* 配置訊息代理
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/receive"); // 呼叫enableSimpleBroker()一個簡單的基於記憶體的訊息代理,將問候訊息帶回以“/ receive”為字首的客戶端
// registry.setApplicationDestinationPrefixes("/app"); //為繫結了@MessageMapping註解方法的訊息指定“/ app”字首,該字首將用於定義所有訊息對映
}
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
}
@Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
}
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
}
@Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
return false;
}
}
複製程式碼
瀏覽器客戶端
伺服器端部分就緒的情況下,向伺服器端傳送訊息並從伺服器端接收訊息的JavaScript客戶端
SockJS是一個瀏覽器JavaScript庫,提供了一個類似WebSocket的物件。SockJS為您提供了一個連貫的,跨瀏覽器的JavaScript API,它在瀏覽器和Web伺服器之間建立了一個低延遲,全雙工,跨域的通訊通道。 在底層SockJS首先嚐試使用本地WebSocket。如果失敗了,它可以使用各種瀏覽器特定的傳輸協議,並通過WebSocket類似的抽象方式呈現它們。
安裝socket-client
npm install sockjs-client
複製程式碼
通過在WebSocket 之上使用 STOMP協議,來為瀏覽器 和 server 間的 通訊增加適當的訊息語義。(STOMP—— Simple Text Oriented Message Protocol——面向訊息的簡單文字協議)
安裝STOMPJS
npm install @stomp/stompjs websocket --save
複製程式碼
前端程式碼如下
const SockJS = require('sockjs-client')
const Stomp = require('@stomp/stompjs')
const socket = new SockJS('http://127.0.0.1:8080/serverStatus')
const stompClient = Stomp.over(socket) //建立STOMP客戶端
stompClient.connect({}, (frame) => { //連線到伺服器
let bean = {
username: 'Test'
}
stompClient.send('/serverStatus', {}, JSON.stringify(bean)) //傳送資訊
stompClient.subscribe('/receive/message', (receive) => { //訂閱並接收訊息
console.log('greeting', JSON.parse(receive.body))
})
})
複製程式碼
#####效果如圖: