欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring Boot整合WebSocket

程序员文章站 2023-10-19 11:13:47
我们首先要知道WebSocket的应用场景: ①在线股票网站 ②即时聊天 ③多人在线游戏 ④应用集群通信 ⑤系统性能及时监控 ...... 下面让我们开始从项目中学习WebSocket: (一)首先创建一个Spring Boot项目,如下图,博主用的是IDEA: 后续过程不太难,如果还是不太会的话, ......

我们首先要知道websocket的应用场景:

       ①在线股票网站

       ②即时聊天

       ③多人在线游戏

       ④应用集群通信

       ⑤系统性能及时监控

       ......

下面让我们开始从项目中学习websocket:

(一)首先创建一个spring boot项目,如下图,博主用的是idea:

          Spring Boot整合WebSocket

          后续过程不太难,如果还是不太会的话,请看https://www.cnblogs.com/*00/p/11317839.html

(二)添加依赖:

          Spring Boot整合WebSocket

 

(三)配置websocket(webscoketmessagebroker.java):

 

 1 package com.example.demo;
 2 
 3 import org.springframework.context.annotation.configuration;
 4 import org.springframework.messaging.simp.config.messagebrokerregistry;
 5 import org.springframework.web.socket.config.annotation.enablewebsocketmessagebroker;
 6 import org.springframework.web.socket.config.annotation.stompendpointregistry;
 7 import org.springframework.web.socket.config.annotation.websocketmessagebrokerconfigurer;
 8 
 9 @configuration
10 @enablewebsocketmessagebroker
11 public class webscoketmessagebroker implements websocketmessagebrokerconfigurer {
12     @override
13     public void configuremessagebroker(messagebrokerregistry config){
14         config.enablesimplebroker("/topic");
15         config.setapplicationdestinationprefixes("/app");
16     }
17     @override
18     public void registerstompendpoints(stompendpointregistry registry){
19         registry.addendpoint("/chat").withsockjs();
20     }
21 }

 

            讲解时间到:

                           ①自定义类websocketconfig继承自websocketmessagebrokerconfigurer进

                              行websocket配置,然后通过@enablewebsocketmessagebgroker注解开启

                              websocket消息代理;

                           ②config.enablesimplebroker("/topic")表示设置消息代理的前缀,即如果消息

                              前缀是"/topic",就会将消息转发给消息代理(broker),再由消息代理将消息广

                              播给当前连接的客户端。

                          ③config.setapplicationdestinationprefixes("/app")表示配置一个或多个前缀,

                              通过这些前缀过滤出需要备注接方法处理的消息。例如,前缀为“/app”的d-

                              estination可以通过@messagemapping注解的方法处理,而其他destination

                              (例如:"/topic" "/queue")将被直接交给broker处理。

                          ④registry.adendpoing("/chat").withsockjs()则表示定义一个前缀为"/chat"的

                              endpoint,并开启sockjs支持,sockjs可以解决浏览器对websocket的兼容性

                              问题,客户户端将通过这里配置的url来建立websocket连接。

(四)定义controller(greetingcontroller.java):

 

 1 package org.sang.wschat.controller;
 2 
 3 import org.sang.wschat.model.chat;
 4 import org.sang.wschat.model.message;
 5 import org.springframework.beans.factory.annotation.autowired;
 6 import org.springframework.messaging.handler.annotation.messagemapping;
 7 import org.springframework.messaging.handler.annotation.sendto;
 8 import org.springframework.messaging.simp.simpmessagingtemplate;
 9 import org.springframework.scheduling.annotation.scheduled;
10 import org.springframework.stereotype.controller;
11 
12 import java.security.principal;
13 
14 @controller
15 public class greetingcontroller {
16     @autowired
17     simpmessagingtemplate messagingtemplate;
18 
19     @messagemapping("/hello")
20     @sendto("/topic/greetings")
21     public message greeting(message message) throws exception {
22         return message;
23     }
24 //    @messagemapping("/chat")
25 //    public void chat(principal principal, chat chat) {
26 //        string from = principal.getname();
27 //        chat.setfrom(from);
28 //        messagingtemplate.convertandsendtouser(chat.getto(), "/queue/chat", chat);
29 //    }
30 }

 

            讲解时间到:

                                 在这一段代码中我们看到@messagemapping("/hello")注解的方法将用来接

                                 收"/app/hello"(上一段代码讲解的第三步)路径发送来的消息,在注解方法

                                 对消息处理后,再将消息转发到@sendto定义的路径上,儿@sendto路径是

                                 一个前缀为"/topic"的路径,所以该消息将被交给消息代理的broker, 之后再

                                由broker进行广播(上一段代码讲解的第三步)。

         快捷聊天界面构建(chat.html):

 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="utf-8">
 5     <title>群聊</title>
 6     <script src="/webjars/jquery/jquery.min.js"></script>          //外部js,添加依赖是有添加
 7     <script src="/webjars/sockjs-client/sockjs.min.js"></script>   //外部js
 8     <script src="/webjars/stomp-websocket/stomp.min.js"></script>  //外部js
 9     <script src="/app.js"></script>
10 </head>
11 <body>
12 <div>
13     <label for="name">请输入用户名:</label>
14     <input type="text" id="name" placeholder="用户名">
15 </div>
16 <div>
17     <button id="connect" type="button">连接</button>
18     <button id="disconnect" type="button" disabled="disabled">断开连接</button>
19 </div>
20 <div id="chat" style="display: none;">
21     <div>
22         <label for="name">请输入聊天内容:</label>
23         <input type="text" id="content" placeholder="聊天内容">
24     </div>
25     <button id="send" type="button">发送</button>
26     <div id="greetings">
27         <div id="conversation" style="display: none">群聊进行中...</div>
28     </div>
29 </div>
30 </body>
31 </html>

         app.js:

 1 var stompclient = null;
 2 function setconnected(connected) {
 3     $("#connect").prop("disabled", connected);
 4     $("#disconnect").prop("disabled", !connected);
 5     if (connected) {
 6         $("#conversation").show();
 7         $("#chat").show();
 8     }
 9     else {
10         $("#conversation").hide();
11         $("#chat").hide();
12     }
13     $("#greetings").html("");
14 }
15 function connect() {
16     if (!$("#name").val()) {
17         return;
18     }
19     // registry.addendpoint("/chat").withsockjs()中的那个"/chat"
20     var socket = new sockjs('/chat');  
21     stompclient = stomp.over(socket);
22     stompclient.connect({}, function (frame) {
23         setconnected(true);
24         // 第一个参数就是目的地地址
25         stompclient.subscribe('/topic/greetings', function (greeting) {
26             showgreeting(json.parse(greeting.body));
27         });
28     });
29 }
30 function disconnect() {
31     if (stompclient !== null) {
32         stompclient.disconnect();
33     }
34     setconnected(false);
35 }
36 function sendname() {
37     // 发送,第一个参数就是greetingcontroller中的发送源地址
38     stompclient.send("/app/hello", {}, json.stringify({'name': $("#name").val(),'content':$("#content").val()}));
39 }
40 function showgreeting(message) {
41     $("#greetings").append("<div>" + message.name+":"+message.content + "</div>");
42 }
43 
44 $(function () {
45     //分别是点击连接、断开连接、发送三个事件,以及对应出发的函数
46     $( "#connect" ).click(function() { connect(); });
47     $( "#disconnect" ).click(function() { disconnect(); });
48     $( "#send" ).click(function() { sendname(); });
49 });

            运行(打开两个页面,进入chat.html,并输入两个用户名,然后点击连接,就可以输入内容了

         ,输入好就可点击发送了):

         Spring Boot整合WebSocket

 

(五) 接下来让我们看一下点对点的传送吧!点对点,所以有了用户,因此用到了spring security,故

           先要添加spring security的依赖;

(六)配置spring securitywebsecurityconfig

 

 1 package org.sang.wschat.config;
 2 
 3 import org.springframework.context.annotation.bean;
 4 import org.springframework.context.annotation.configuration;
 5 import org.springframework.security.config.annotation.authentication.builders.authenticationmanagerbuilder;
 6 import org.springframework.security.config.annotation.web.builders.httpsecurity;
 7 import org.springframework.security.config.annotation.web.configuration.websecurityconfigureradapter;
 8 import org.springframework.security.crypto.bcrypt.bcryptpasswordencoder;
 9 import org.springframework.security.crypto.password.passwordencoder;
10 
11 @configuration
12 public class websecurityconfig extends websecurityconfigureradapter {
13     @bean
14     passwordencoder passwordencoder() {
15         return new bcryptpasswordencoder();
16     }
17     @override
18     protected void configure(authenticationmanagerbuilder auth) throws exception {
19         auth.inmemoryauthentication()
20         .withuser("admin")
21         .password("$2a$10$rmufxgq5ath4wovkuqyvuecpquseoxzyqilxzbz50dcersga.wyiq") //即123
22         .roles("admin")
23         .and()
24         .withuser("sang")
25         .password("$2a$10$rmufxgq5ath4wovkuqyvuecpquseoxzyqilxzbz50dcersga.wyiq") //即123
26         .roles("user");
27     }
28     @override
29     protected void configure(httpsecurity http) throws exception {
30         http.authorizerequests()
31                 .anyrequest().authenticated()
32                 .and()
33                 .formlogin().permitall();
34     }
35 }

 

(七)改造websocket(websocketconfig.java):

 1 package org.sang.wschat.config;
 2 
 3 import org.springframework.context.annotation.configuration;
 4 import org.springframework.messaging.simp.config.messagebrokerregistry;
 5 import org.springframework.web.socket.config.annotation.enablewebsocketmessagebroker;
 6 import org.springframework.web.socket.config.annotation.stompendpointregistry;
 7 import org.springframework.web.socket.config.annotation.websocketmessagebrokerconfigurer;
 8 
 9 @configuration
10 @enablewebsocketmessagebroker
11 public class websocketconfig implements websocketmessagebrokerconfigurer {
12     @override
13     public void configuremessagebroker(messagebrokerregistry config) {
14         config.enablesimplebroker("/topic","/queue");  //就这里多加了个"/queue"
15         config.setapplicationdestinationprefixes("/app");
16     }
17     @override
18     public void registerstompendpoints(stompendpointregistry registry) {
19         registry.addendpoint("/chat").withsockjs();
20     }
21 }

(八)配置controller:

 1 package org.sang.wschat.controller;
 2 
 3 import org.sang.wschat.model.chat;
 4 import org.sang.wschat.model.message;
 5 import org.springframework.beans.factory.annotation.autowired;
 6 import org.springframework.messaging.handler.annotation.messagemapping;
 7 import org.springframework.messaging.handler.annotation.sendto;
 8 import org.springframework.messaging.simp.simpmessagingtemplate;
 9 import org.springframework.scheduling.annotation.scheduled;
10 import org.springframework.stereotype.controller;
11 
12 import java.security.principal;
13 
14 @controller
15 public class greetingcontroller {
16     @autowired
17     simpmessagingtemplate messagingtemplate;
18 
19     @messagemapping("/hello")
20     @sendto("/topic/greetings")
21     public message greeting(message message) throws exception {
22         return message;
23     }
24     @messagemapping("/chat")
25     public void chat(principal principal, chat chat) {
26         string from = principal.getname();
27         chat.setfrom(from);
28         messagingtemplate.convertandsendtouser(chat.getto(), "/queue/chat", chat);  
29     }
30 }

(九)创建聊天界面(类似于chat.html,此处是onlinechat.html):

 1 <!doctype html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="utf-8">
 5     <title>单聊</title>
 6     <script src="/webjars/jquery/jquery.min.js"></script>
 7     <script src="/webjars/sockjs-client/sockjs.min.js"></script>
 8     <script src="/webjars/stomp-websocket/stomp.min.js"></script>
 9     <script src="/chat.js"></script>
10 </head>
11 <body>
12 <div id="chat">
13     <div id="chatscontent">
14     </div>
15     <div>
16         请输入聊天内容:
17         <input type="text" id="content" placeholder="聊天内容">
18         目标用户:
19         <input type="text" id="to" placeholder="目标用户">
20         <button id="send" type="button">发送</button>
21     </div>
22 </div>
23 </body>
24 </html>

(十)该轮到chat.js了,类似于点对点之前的那个项目的app.js:

 1 var stompclient = null;
 2 function connect() {
 3     var socket = new sockjs('/chat');
 4     stompclient = stomp.over(socket);
 5     stompclient.connect({}, function (frame) {
 6         stompclient.subscribe('/user/queue/chat', function (chat) {
 7             showgreeting(json.parse(chat.body));
 8         });
 9     });
10 }
11 function sendmsg() {
12     stompclient.send("/app/chat", {}, json.stringify({'content':$("#content").val(), 'to':$("#to").val()}));
13 }
14 function showgreeting(message) {
15     $("#chatscontent").append("<div>" + message.from+":"+message.content + "</div>");
16 }
17 $(function () {
18     connect();
19     $( "#send" ).click(function() { sendmsg(); });
20 });

            注:点对点这里要注意,第6行,路径是"/user/queue/chat",因为这个destinationprefix默认值是

          "/user",也就是说消息的最终发送路径是"/user/用户名/queue.chat"

          结果如下:

          Spring Boot整合WebSocket

 

add:其实这个里面还有两个mode,一个是message的,另一个是chat的,读者可以下载完整源代码自

           行研究,这个项目的完整源代码地址:https://github.com/stray-kite/wschat