websocket
瀏覽器 與 服務器 全雙工 通信
沒有實現該協議的,用 STOMP協議來
引用:org.springframework.boot
spring-boot-starter-websocket
1. 定義服務端點的配置類
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
2.定義服務端點的位置
@ServerEndpoint("/ws") //創建服務端點 地址爲/ws
@Service
public class WebSocketServiceImpl {
private static CopyOnWriteArraySet<WebSocketServiceImpl>
webSocketSet = new CopyOnWriteArraySet<>();
private Session session;
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this); // 加入set中
sendMessage("有新的連接加入了!!");
}
@OnClose
public void onClose() {
webSocketSet.remove(this); // 從set中刪除
}
@OnMessage
public void onMessage(String message, Session session) {
// 羣發消息
for (WebSocketServiceImpl item : webSocketSet) {
item.sendMessage(message);
}
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
private void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
}
@OnMessage 就是收到客戶端發的消息,
幹嘛了呢?遍歷所有的socket使用
session.getBasicRemote().sendText(message);
進行了羣發。
3. 前端代碼。需要引用 jquery-3.2.1.min.js或任意版本,可以請求引用 src="https://code.jquery.com/jquery-3.2.1.min.js"
var websocket = null;
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/ws");
} else {
alert('Not support websocket')
}
websocket.onerror=XX
websocket.onopen=XX
websocket.onmessage = function(event) {
appendMessage(event.data);
}
websocket.onclose = function() {
appendMessage("close");
}
// 監聽窗口關閉事件,主動去關閉websocket連接,
window.onbeforeunload = function() {
websocket.close();
}
// 關閉連接
function closeWebSocket() {
websocket.close();
}
// 顯示
function appendMessage(message) {
var context = $("#context").html() +"<br/>" + message;
$("#context").html(context);
}
// 發送消息
function sendMessage() {
var message = $("#message").val();
websocket.send(message);
}
創建連接地址:
new WebSocket("ws://localhost:8080/ws");
發送消息:
websocket.send(message);
會發到後臺點的@OnMessage方法。
使用 STOMP
瀏覽器不支持WebSocket協議,使用其子協議STOMP
1. 啓用子協議。配置端點路徑(/socket很重要)。
2. 配置客戶端路徑前綴。服務端請求前綴。
@Configuration
@EnableWebSocketMessageBroker //啓用STOMP協議
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socket").withSockJS(); //也可以支持sockJS
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 客戶端訂閱路徑前綴
registry.enableSimpleBroker("/sub");
// 服務端點請求前綴
registry.setApplicationDestinationPrefixes("/request");
}
}
3. Controller配置請求路徑send。加上上面的配置即爲:/request/send
和 前端要監控的路徑 (/sub/chat) 。sub與上面配置一樣。
@Controller
@RequestMapping("/websocket")
public class WebSocketController {
// 定義消息請求路徑
@MessageMapping("/send")
// 定義結果發送到特定路徑
@SendTo("/sub/chat")
public String sendMsg(String value) {
return value;
}
}
4. 前端js的發送端:需要引用jquery 和 sockjs.min.js
(可以請求引用 src="https://cdn.jsdelivr.net/sockjs/1/sockjs.min.js")。
和stomp.min.js ,不可請求引用(因爲請求引用了就變成文本了)
var stompClient = null;
function connect() {
var socket = new SockJS('/socket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
});
}
function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
}
function sendMsg() {
var value = $("#message").val();
stompClient.send("/request/send", {}, value);
}
connect();
核心代碼會,創建socketJs
var socket = new SockJS('/socket');
使用stomp協議
stompClient = Stomp.over(socket);
發送消息:
stompClient.send("/request/send", {}, value);
會請求到後臺@MessageMapping("/send")
5. 前端接收的js
var noticeSocket = function() {
var s = new SockJS('/socket');
var stompClient = Stomp.over(s);
stompClient.connect({}, function() {
stompClient.subscribe('/sub/chat', function(data) {
$('#receive').html(data.body);
});
});
};
noticeSocket();
接收也要創建 stompClient,代碼和路徑同樣。
發送的js只定義了往後臺發,而接收端,則定義了 等待後臺發消息的路徑。
stompClient.subscribe('/sub/chat', 函數)
很顯然,這個路徑與後臺的: @SendTo("/sub/chat") 匹配。
stomp指定用戶發送消息:
sockJS 是一個 第三方關於 支持 WebSocket請求的 Js 框架
boot 提供 SimpMessaging Template對象
1.配置
在創建一個服務端點
registry.addEndpoint("/wsuser").withSockJS();
客戶端的訂閱路徑也創建一個(原來只有一個sub)
registry.enableSimpleBroker("/sub", "/queue");
2.引入security,並配置2個用戶
extends WebSecurityConfigurerAdapter
重寫方法:
configure(AuthenticationManagerBuilder auth)
PasswordEncoder pe= new BCryptPasswordEncoder();
// 可以通過 pe.encode("p1")這樣獲得加密後的密碼
auth.inMemoryAuthentication().passwordEncoder(pe)
.withUser("user1") .password("XXX").roles("USER")
.and()
.withUser("user2").password("XXX").roles("ADMIN");
3. controler 路徑
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/sendUser")
public void sendToUser(Principal principal, String body) {
String srcUser = principal.getName();
String []args = body.split(",");
String desUser = args[0];
String message = srcUser + "發來消息:" + args[1];
// 發送到用戶和監聽地址
simpMessagingTemplate.convertAndSendToUser(desUser,
"/queue/customer", message);
}
/queue 與配置訂閱路徑對應
4. js發送端
var stompClient = null;
// 開啓socket連接
function connect() {
// 連接/wsuser服務端點
var socket = new SockJS('/wsuser');
// stomp客戶端
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
});
}
// 斷開socket連接
function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
}
// 向‘/request/sendUser’服務端發送消息
function sendMsg() {
var value = $("#message").val();
var user = $("#user").val();
// 用戶和消息組成的字符串
var text = user +"," + value;
stompClient.send("/request/sendUser", {}, text);
}
connect();
代碼和上個幾乎一樣。
只是:獲取了 消息 和用戶名。用逗號拼接,發送到
stompClient.send("/request/sendUser", {}, text);
服務端的前綴依然沒變/request
與後臺的 @MessageMapping("/sendUser")對應
後臺用 String body 接收了 text,並且拆分 ,然後得到用戶名進行發送。
messagingTemplate 發送需要3個參數,至此都有了。
simpMessagingTemplate.convertAndSendToUser(desUser,
"/queue/customer", message);
下面看這個接收地址:/customer
5. js接收端
var noticeSocket = function() {
var s = new SockJS('/wsuser');
var stompClient = Stomp.over(s);
stompClient.connect({}, function() {
stompClient.subscribe('/user/queue/customer', function(data) {
$('#receive').html(data.body);
});
});
};
noticeSocket();
代碼按照後臺指定的位置接收消息,但是需要自己加路徑 /user
由此我們可以發現,客戶端是可以沒必要配置的,爲了更加簡潔,便註釋了此代碼。
registry.enableSimpleBroker("/sub", "/queue");
深入淺出boot2.0 第13章 websocket我的整理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.