背景
我們都知道http協議只能在瀏覽器單方面向服務器發起請求時獲得響應,然而服務器不能主動向瀏覽器推送消息,想要實現瀏覽器的主動推送目前有兩種主流的實現方式:
- 輪詢:缺點很多,但是實現簡單
- websocket: 在瀏覽器和服務器之間建立TCP連接,實現全雙工通信
springboot使用websocket有兩種方式,一種是實現簡單的websocket,另外一種是實現STOMP協議。本篇講述如何使用springboot實現簡單的websocket。
實現
一、導入依賴
直接在pom.xml
中導入依賴。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
二、新建WebSocket配置類,注入Bean
首先注入一個ServerEndpointExporterBean,該Bean會自動注冊使用@ServerEndpoint注解申請的websocket endpoint,代碼如下:
@Component
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
三、新建WebSocket服務端,在其中處理websocket邏輯
@Component //注冊到容器中
@ServerEndpoint("/webSocket") //接收websocket請求路徑
@Slf4j
public class WebSocket {
//當前連接(每個websocket連入都會創建一個WebSocket實例)
private Session session;
//定義一個websocket容器存儲session,即存放所有在線的socket連接
private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<>();
//處理連接建立
@OnOpen
public void opOpen(Session session){
this.session = session;
log.info("【有新的客戶端連接了】:{}",session.getId());
webSocketSet.add(this); //將新用戶加入在線組
log.info("【websocket消息】有新的連接,總數:{}",webSocketSet.size());
}
//處理連接關閉
@OnClose
public void Onclose(){
webSocketSet.remove(this);
log.info("【websocket消息】連接斷開,總數:{}",webSocketSet.size());
}
//接受消息
@OnMessage
public void onMessage(String message){
log.info("【websocket消息】收到客戶端發來的消息:{}",message);
}
// 群發消息
public void sendMessage(String message) {
for (WebSocket webSocket : webSocketSet) {
log.info("【websocket消息】廣播群發消息,message={}",message);
try {
webSocket.session.getBasicRemote().sendText(message);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
四、客戶端實現,可以借助FreeMarker模板工具直接寫在ftl文件里。
由於部分瀏覽器可能不支持,可以先測試,代碼如下:
<script>
var websocket = null;
if('WebSocket' in window){
websocket = new WebSocket('ws://localhost:8080/webSocket');
}else{
alert('當前瀏覽器不支持websocket消息通知');
}
//連接成功建立的回調方法
websocket.onopen = function (event) {
console.log("ws建立連接成功");
}
//連接關閉的回調方法
websocket.onclose = function (event) {
console.log("ws連接關閉");
}
//接收到消息的回調方法
websocket.onmessage = function (event) {
/*setMessageInnerHTML(event.data);*/
// alert("ws接收返回消息:"+event.data);
console.log("服務器返回消息: " + event.data);
//彈窗提醒(要用到JQuary,所以要先引入JQuary) 播放音樂
$('#mymodal').modal('show')
}
//連接發生錯誤的回調方法
websocket.onerror = function(event){
alert('websocket通信發生錯誤!')
}
//監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。
window.onbeforeunload = function() {
websocket.close();
}
</script>
五、測試(項目實現客戶創建新訂單之后,前台發出提醒)
@Autowired
private WebSocket webSocket;
@Override
@Transactional
public OrderDTO create(OrderDTO orderDTO) {//創建訂單
。。。。(具體代碼省略)
//創建新訂單 發送websocket消息
webSocket.sendMessage(orderDTO.getOrderId());
return orderDTO;
}
添加新訂單:
接收到websocket消息