之前在做站內信時,用到了 WebSocket ,整理了一些筆記分享如下。
本文基於 SpringBoot 2.1.5,本文不涉及環境搭建。
引入依賴
在 Spring 中要使用 WebSocket 功能,需要在pom中引入依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
配置類
增加一個配置類,用於定義 WebSocket 全局配置信息
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
/**
* 注冊stomp端點
* @param registry
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
## 允許使用socketJs方式訪問 即可通過http://IP:PORT/xboot/ws來和服務端websocket連接
registry.addEndpoint("/tmax/ws").setAllowedOrigins("*").withSockJS();
}
/**
* 配置信息代理
* @param registry
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
## 訂閱Broker名稱 user點對點 topic廣播即群發
registry.enableSimpleBroker("/user","/topic");
## 全局(客戶端)使用的消息前綴
registry.setApplicationDestinationPrefixes("/app");
## 點對點使用的前綴 無需配置 默認/user
registry.setUserDestinationPrefix("/user");
}
}
來看一下這兩個方法:
1、registerStompEndpoints(StompEndpointRegistry registry)
注冊stomp端點。起到的作用就是添加一個服務端點,來接收客戶端的連接,
registry.addEndpoint("/tmax/ws") 表示添加了一個 /tmax/ws 端點,客戶端可以通過這個端點來進行連接。withSockJS() 的作用是開啟 SockJS 訪問支持,即可通過http://IP:PORT/tmax/ws 來和服務端 websocket 連接。
2、configureMessageBroker(MessageBrokerRegistry registry)
配置信息代理。定義消息代理,設置消息連接請求的各種規范信息。
registry.enableSimpleBroker("/user","/topic") 表示客戶端訂閱地址的前綴信息,也就是客戶端接收服務端消息的地址的前綴信息(比較繞,看完整個例子,大概就能明白了)registry.setApplicationDestinationPrefixes("/app") 指服務端接收地址的前綴,意思就是說客戶端給服務端發消息的地址的前綴。
registry.setUserDestinationPrefix("/user") 指推送用戶前綴。
我不不難發現,setApplicationDestinationPrefixes 與 setUserDestinationPrefix 起到的效果敲好相反,一個定義了客戶端接收的地址前綴,一個定義了客戶端發送地址的前綴。
開始業務代碼的編寫
先了解幾個知識點,下方會用到。
1、MessageMapping
接收客戶端請求連接注解。Spring 對於 WebSocket 封裝的特別簡單,提供了一個 @MessageMapping 注解,功能類似 @RequestMapping,它是存在於Controller中的,定義一個消息的基本請求,功能也跟 @RequestMapping類似,包括支持通配符 的url定義等等。
2、SimpMessagingTemplate
SimpMessagingTemplate 是 Spring-WebSocket 內置的一個消息發送工具,可以將消息發送到指定的客戶端。
3、SendTo
@SendTo 可以把消息廣播到路徑上去,例如下面可以把消息廣播到 "/topic/greetings”,如果客戶端在這個路徑訂閱消息,則可以接收到消息
接下來看一下后台代碼實現,HelloController
/**
* @author niceyoo
*/
@Slf4j
@Controller
@Api(description = "hello接口")
@Transactional
public class HelloController {
@Autowired
private SimpMessagingTemplate messagingTemplate;
/**
* 跳轉至hello.html界面
* @return
*/
@RequestMapping("/hello")
public String hello(){
return "hello";
}
/**
* 接收然后轉發至客戶端消息
* @param message
* @return
* @throws Exception
*/
@MessageMapping("/top")
@SendTo("/topic/greetings")
public String greeting(String message) throws Exception {
System.out.println("receiving " + message);
System.out.println("connecting successfully.");
return "AAA:"+message;
}
/**
* 推送消息
* @return
*/
@ResponseBody
@RequestMapping("/hello/addMessage")
public Result<Object> addMessage(){
messagingTemplate.convertAndSend("/topic/greetings", "您收到了新的系統消息");
return new ResultUtil<Object>().setSuccessMsg("添加成功");
}
}
hello.html 代碼:
<!doctype html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/sockjs-client/1.3.0/sockjs.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.js"></script>
<style>
.box {
width: 300px;
float: left;
margin: 0 20px 0 20px;
}
.box div, .box input {
border: 1px solid;
-moz-border-radius: 4px;
border-radius: 4px;
width: 100%;
padding: 0px;
margin: 5px;
}
.box div {
border-color: grey;
height: 300px;
overflow: auto;
}
.box input {
height: 30px;
}
h1 {
margin-left: 30px;
}
body {
background-color: #F0F0F0;
font-family: "Arial";
}
</style>
</head>
<body lang="en">
<h1>Index</h1>
<div id="first" class="box">
<div></div>
<input autocomplete="off" value="Type here..."></input>
<button onclick="connect()">登陸客戶端</button>
<button onclick="send()">發送消息</button>
</div>
<script>
var stompClient = null;
var sockjs_url = '/tmax/ws';
function connect() {
var sockjs = new SockJS(sockjs_url);
stompClient = Stomp.over(sockjs);
stompClient.connect({}, function(frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function(greeting){
console.log("返回內容:"+greeting.body);
print('服務器:', greeting.body);
});
});
}
function send() {
if(stompClient == null){
print('系統提示:', '請先點擊客戶端登陸');
return false;
}
print('客戶端:', inp.val());
stompClient.send("/app/top", {}, inp.val());
inp.val('');
}
$('#first input').focus();
var div = $('#first div');
var inp = $('#first input');
var print = function(m, p) {
p = (p === undefined) ? '' : p;
div.append($("<code>").text(m + ' ' + p));
div.append($("<br>"));
div.scrollTop(div.scrollTop()+10000);
};
</script>
</body>
</html>
操作流程:

點擊“登錄客戶端”,輸入框內輸入內容,點擊發送消息。
消息推送
關於消息的推送,借助 postman,調用 http://127.0.0.1:8888/hello/addMessage,實現后端推送至客戶端。

額外補充,關於消息推送,往往會用到推送至指定用戶,則:messagingTemplate.convertAndSendToUser(id,"/queue/subscribe", "您收到了新的消息"); ,其中id為系統用戶id。
詳細可搜索 SimpMessagingTemplate 的一些用法。
如果文章有錯的地方歡迎指正,大家互相留言交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:niceyoo

參考地址:https://www.jianshu.com/p/60799f1356c5