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我的整理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.