Spring Boot WebSocket Vue 前后端分离实现消息通讯
Spring Boot 2.0 WebSocket Vue 前后端分离实现消息通讯一、前言二、快速开始三、注意事项讲一下过程中踩得坑一、前言目前项目中要实现一个消息推送的功能,类似于空间点赞,朋友圈新消息的提醒功能,然后马上想到websocket长连接实现的实时通讯效果,引入到了项目之中,我也做了一个小的demo,大家可以参考一下。二、快速开始在springboot项目中添加webso...
一、前言
目前项目中要实现一个消息推送的功能,类似于空间点赞,朋友圈新消息的提醒功能,然后马上想到websocket长连接实现的实时通讯效果,引入到了项目之中,我也做了一个小的demo,大家可以参考一下。
二、快速开始
-
在springboot项目中添加websocket所需要的依赖;
<!-- websocket --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
-
添加websocket配置类;
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { /** * 配置信息代理 */ @Override public void configureMessageBroker(MessageBrokerRegistry config) { // 订阅Broker名称,接受消息用户必须以这个开头的路径才能收到消息 config.enableSimpleBroker("/user", "/topic", "/queue"); // 全局使用的消息前缀(客户端订阅路径上会体现出来),客户端主动发送消息会以这里配置的前缀访问 @MessageMapping 配置的路径 config.setApplicationDestinationPrefixes("/app"); // 点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/ config.setUserDestinationPrefix("/user"); } /** * 注册stomp的端点 */ @Override public void registerStompEndpoints(StompEndpointRegistry registry) { // 允许使用socketJs方式访问,endpointSang,允许跨域 // 在网页上我们就可以通过这个链接 // http://localhost:8080/endpointSang // 来和服务器的WebSocket连接 registry.addEndpoint("/endpointSang") // .addInterceptors(new HttpSessionHandshakeInterceptor()) .setAllowedOrigins("*") // 允许跨域设置 .withSockJS(); } }
-
写一个控制器进行广播通讯(一个人发送消息,多个人收消息),点对点通讯(一人发一人收),可以用 SimpMessagingTemplate 或者 @SendTo("/topic/greetings") 2种方式都可以进行推送消息。
@RestController public class WsController { private final Logger logger = LoggerFactory.getLogger(WsController.class); @Autowired private SimpMessagingTemplate messageTemplate; /** * 广播 * @param message * @return */ @MessageMapping("/welcome") @SendTo("/topic/greetings") public Map say(Map message) { logger.info(message.get("chatType").toString()); Map res = new HashMap(); res.put("topic", message.get("chatType").toString()); return res; } /** * 请求接口推送消息-(广播) * @param message */ @GetMapping("/sentMes") public void sentMes(String message) { logger.info(message + "xiaixixi"); this.messageTemplate.convertAndSend("/queue/msg", message); } /** * 点对点通信 * @param message */ @MessageMapping(value = "/point") @SendToUser("/topic/point") public String point(Map message) { logger.info(message.get("test") + "******"); return "dd"; } /** * 点对点通信 * @param message */ @MessageMapping(value = "/points") public void point1(Map message) { logger.info(message.get("name") + "******" ); //发送消息给指定用户, 最后接受消息的路径会变成 /user/admin/queue/points messageTemplate.convertAndSendToUser("admin", "/queue/points", message); } }
备注:如果是前端主动推送消息,可以用控制器请求进行处理,也可以用websocket,特有的@MessageMapping("/welcome"),第二种可以实现点对点的通讯效果。
-
前端vue进行代码处理;
可以在所需要的项目中直接下载依赖,如果没有的话可以直接在新建一个工程。
如果不会的这里有: vue如何新建一个项目.
下载依赖:npm install sockjs-client --save npm install stompjs --save npm install axios --save
-
创建vue页面引入依赖,编写主要方法;
请求接口收消息<template> <div class="hello"> <h1>{{ msg }}</h1> 请求参数:<input type="text" v-model="params"/> <button @click="axiosGet">axios请求</button> <ul> <li v-for="(item,i) in listData">{{item}}</li> </ul> <p><router-link to="/ws">自动发消息,收消息(广播)</router-link></p> <p><router-link to="/wsp">点对点,收消息发消息</router-link></p> </div> </template> <script> import SockJS from 'sockjs-client' import Stomp from 'stompjs' import axios from 'axios' export default { name: 'HelloWorld', data() { return { msg: '广播', params: '你好', listData: ['whdoftinc'], stompClient: '', timer: '' } }, methods: { init() { // 建立连接对象 let socket = new SockJS('http://127.0.0.1:8080/endpointSang') // 获取STOMP子协议的客户端对象 this.stompClient = Stomp.over(socket) // 向服务器发起websocket连接 this.stompClient.connect({}, () => { this.stompClient.subscribe('/queue/msg', (msg) => { // 订阅服务端提供的某个queue console.log('******** 成功收到消息 *****', msg) console.log(msg.body) // msg.body存放的是服务端发送给我们的信息 this.listData.push(msg.body) }) }, (err) => { // 连接发生错误时的处理函数 console.log('失败') console.log(err); }) }, axiosGet() { axios.get('http://localhost:8080/sentMes?message='+this.params) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }) } }, // 初始化连接 mounted() { this.init(); }, } </script>
自动发消息,收消息(广播)
<template> <div> <p>{{message}}</p> <p><router-link to="/wsp">点对点,收消息发消息</router-link></p> <p><router-link to="/">请求接口收消息</router-link></p> </div> </template> <script> import SockJS from 'sockjs-client'; import Stomp from 'stompjs'; export default { name: 'HelloWorld', data() { return { message: '', stompClient:'', timer:'' } }, methods: { initWebSocket() { this.connection(); let that= this; // 断开重连机制,尝试发送消息,捕获异常发生时重连 this.timer = setInterval(() => { try { that.stompClient.send("/app/welcome",{},JSON.stringify({sender: '',chatType: 'JOIN'}),) //用户加入接口 console.log("******发送消息******") } catch (err) { console.log("断线了: " + err) that.connection() } }, 5000); }, // 连接服务器 connection() { // 建立连接对象 let socket = new SockJS('http://127.0.0.1:8080/endpointSang'); // 获取STOMP子协议的客户端对象 this.stompClient = Stomp.over(socket); // 定义客户端的认证信息,按需求配置 let headers = { Authorization:'' } let that = this // 向服务器发起websocket连接 this.stompClient.connect(headers,() => { this.stompClient.subscribe('/topic/greetings', function(data) { //订阅消息 console.log(data, "******收到消息了********") that.message += data.body }) }, (err) => { // 连接发生错误时的处理函数 console.log('失败') console.log(err) }); }, // 断开连接 disconnect() { if (this.stompClient) { this.stompClient.disconnect() } } }, // 初始化连接 mounted(){ this.initWebSocket() }, beforeDestroy: function () { // 页面离开时断开连接,清除定时器 this.disconnect() clearInterval(this.timer) } } </script>
点对点,收消息发消息
<template> <div> <div>{{msg}}</div> <p><router-link to="/ws">自动发消息,收消息(广播)</router-link></p> <p><router-link to="/">请求接口收消息</router-link></p> </div> </template> <script> import SockJS from 'sockjs-client'; import Stomp from 'stompjs'; export default { name: 'HelloWorld', data() { return { msg: "你好", stompClient:'', timer:'' } }, methods: { initWebSocket() { this.connection() let that= this // 断开重连机制,尝试发送消息,捕获异常发生时重连 this.timer = setInterval(() => { try { that.stompClient.send("/app/points", {},JSON.stringify({name: 'admin'}),) //用户加入接口 } catch (err) { console.log("断线了: " + err) that.connection(); } }, 5000); }, // 连接服务器 connection() { // 建立连接对象 let socket = new SockJS('http://127.0.0.1:8080/endpointSang') // 获取STOMP子协议的客户端对象 this.stompClient = Stomp.over(socket); // 定义客户端的认证信息,按需求配置 let headers = { name:'admin' } let that = this // 向服务器发起websocket连接 this.stompClient.connect(headers,() => { // 这里的路径需要和后台 发送人保持一致 this.stompClient.subscribe('/user/admin/queue/points', function(data) { //订阅消息 console.log(data, "******收到消息了********") that.msg += data.body },headers); }, (err) => { // 连接发生错误时的处理函数 console.log('失败') console.log(err) }); }, // 断开连接 disconnect() { if (this.stompClient) { this.stompClient.disconnect(); } } }, // 初始化连接 mounted(){ this.initWebSocket() }, beforeDestroy: function () { // 页面离开时断开连接,清除定时器 this.disconnect() clearInterval(this.timer) } } </script>
以上是主要核心代码,效果大家可以自己尝试一下。
三、注意事项
讲一下过程中踩得坑
- 前端发送请求的时候以@MessageMapping(value = “/point”) 要以websocket中配置的config.setApplicationDestinationPrefixes("/app");
路径则为/app/point进行请求。 - 前端接受消息的时候一定要以配置的this.messageTemplate.convertAndSend("/queue/msg", message);
开头路径的这个/queue,
config.enableSimpleBroker("/user", “/topic”, “/queue”); 这里面一定要存在。可以配置多个。 - 广播通讯开始的很顺利,然后进行点对点通讯发消息的时候,始终接受不到消息,搞了半天才发现,一定要遵循上述所提出的config.enableSimpleBroker("/user", “/topic”, “/queue”); 所配置的路径才可以收到消息,发给指定用户默认会在路径加上/user/
config.setUserDestinationPrefix("/user"); 这里可以自定义配置,但是如果配置了其它路径,一定要设置到config.enableSimpleBroker 中。
例如:
config.enableSimpleBroker("/user", “/topic”, “/queue”);
config.setUserDestinationPrefix("/user");
messageTemplate.convertAndSendToUser(“admin”, “/queue/points”, message);
最后前端接受消息的时候路径会变成/user/admin/queue/points
user 这个路径一定要出现在config.enableSimpleBroker 中,否则收不到消息
四、代码demo参考
本文代码地址:https://github.com/wuhengc/springboot-websocket-vue
个人博客地址:https://www.whsoftinc.com
如有疑问请联系我:33993155(微信同号)
更多推荐
所有评论(0)