目前项目中要实现一个消息推送的功能,类似于空间点赞,朋友圈新消息的提醒功能,然后马上想到websocket长连接实现的实时通讯效果,引入到了项目之中,我也做了一个小的demo,大家可以参考一下。
在springboot项目中添加websocket所需要的依赖;
org.springframework.boot
spring-boot-starter-websocket
添加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>
以上是主要核心代码,效果大家可以自己尝试一下。
例如:
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(微信同号)