學而不思則罔,思而不學則殆。
一、背景介紹
java 大部分都是在做服務端,主要的流程也都是用戶端發起一個http請求,服務端接收請求,然後響應資料
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxyMwhkWuhmMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL4gTO3MzM1QTM3ITMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
如果這個時候服務端想往用戶端發送資料,比較常見的就是有
- 輪序: 也就是用戶端一直往服務端請求擷取要的資料,這樣服務端壓力大
- 長連接配接: 用 iframe 的方式 保持一個持久的連接配接,對服務端壓力也大.
- webSocket: 這個就是這篇文章要講的,以TCP的方式 建立連接配接之後就可以雙向通信了
springboot java websocket ws 快速入門 (一)
二、最佳實踐
2.1 引入依賴
<!-- spring boot 的依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- websocket 的依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.2 啟動類上添加注解 @EnableWebSocket 和注入ServerEndpointExporter
@SpringBootApplication
@EnableWebSocket
@MapperScan("com.example.demo.dao")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
/**
* 初始化Bean,它會自動注冊使用了 @ServerEndpoint 注解聲明的 WebSocket endpoint
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
2.3 編寫服務端執行個體
package com.example.demo.websocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @Classname WebSocketTest
* @Description webSocket 測試類
* @Date 2020/11/27 13:23
* @Created by dongzhiwei
*/
@ServerEndpoint(value="/websocket/{id}")
@Slf4j
@Component
public class WebSocketTest {
private static int onlineCount = 0;
private static Map<String, WebSocketTest> webSocketMap = new ConcurrentHashMap<>();
private Session session;
private String id;
/**
* 使用者第一次建立連接配接的時候執行的方法
* @param id
* @param session
*/
@OnOpen
public void onOpen(@PathParam("id") String id, Session session){
this.id = id;
this.session = session;
if (!webSocketMap.containsKey(id)) {
//沒有建立連接配接的
webSocketMap.put(id, this);
//注意并發
addOnlineCount();
}
log.info("使用者"+id+"連接配接上webSocket,目前連接配接人數為"+getOnlineCount());
}
/**
* 連接配接關閉調用的方法
*/
@OnClose
public void onClose() {
if(webSocketMap.containsKey(this.id)){
webSocketMap.remove(this.id);
//從set中删除
subOnlineCount();
}
log.info("使用者退出:"+id+",目前線上人數為:" + getOnlineCount());
}
/**
* 收到用戶端消息後調用的方法
*
* @param message 用戶端發送過來的消息*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("使用者"+this.id+"發送資訊:"+message);
}
/**
* 發生錯誤的時候調用的方法
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("使用者錯誤:"+this.id+",原因:"+error.getMessage());
error.printStackTrace();
}
/**
* 向執行某個任務的用戶端發送消息
*/
public void sendMessage(String message){
this.session.getAsyncRemote().sendText(message);
}
/**
* 向使用者id為userId的使用者推送消息
* */
public static void sendInfo(String message,String id){
log.info("發送消息到:"+id+",封包:"+message);
if(id != null && webSocketMap.containsKey(id)){
webSocketMap.get(id).sendMessage(message);
}else{
log.error("使用者"+id+",不線上!");
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketTest.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketTest.onlineCount--;
}
}
2.4 測試連接配接
啟動服務,根據ip位址和端口建立socket 連接配接, 點這裡線上網站測試
三、總結
其實在一個http服務端上面再部署一下ws 也是沒有問題的通路也沒有任何問題 他們就是兩個不同的協定 一個http協定 一個websocket協定.我們可以在類似于聊天室和浏覽器實時擷取最新消息的時候用到這個ws協定.無論怎麼用都隻是一個工具,在這個場景下是否适用罷了。