深入浅出boot2.0 第13章 websocket我的整理


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() +"
"
+ 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我的整理)