springboot集成websocket点对点推送、广播推送
程序员文章站
2022-07-02 15:19:07
一、什么都不用说,导入个依赖先 二、推送到前端的消息实体类 三、因为要实现点对点的推送,所以需要创建一个监听器来获取到websocket的session,如下: 四、最重要的配置类 代码中有详细的解释,认真看可以看明白的。 五、controller 六、前端页面 最好,来试试点对点推送。 第一个页面 ......
一、什么都不用说,导入个依赖先
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-websocket</artifactid>
</dependency>
二、推送到前端的消息实体类
import lombok.allargsconstructor;
import lombok.builder;
import lombok.data;
import lombok.noargsconstructor;
import java.io.serializable;
@data
@builder
@noargsconstructor
@allargsconstructor
public class notifybean<t> implements serializable {
private static final long serialversionuid = 1l;
private int type;
private string message;
private t data;
}
三、因为要实现点对点的推送,所以需要创建一个监听器来获取到websocket的session,如下:
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.context.applicationlistener;
import org.springframework.messaging.simp.stomp.stompheaderaccessor;
import org.springframework.web.socket.messaging.sessionconnectevent;
public class stompconnecteventlistener implements applicationlistener<sessionconnectevent> {
@autowired
private redishelper redishelper;
@override
public void onapplicationevent(sessionconnectevent event) {
stompheaderaccessor sha = stompheaderaccessor.wrap(event.getmessage());
//login get from browser
if(sha.getnativeheader("userid")==null){
return;
}
string userid = sha.getnativeheader("userid").get(0);
string sessionid = sha.getsessionid();
redishelper.redistemplate.opsforvalue().set("websocket:"+userid,sessionid);
}
}
四、最重要的配置类
import lombok.extern.slf4j.slf4j;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.messaging.message;
import org.springframework.messaging.messagechannel;
import org.springframework.messaging.simp.config.channelregistration;
import org.springframework.messaging.simp.config.messagebrokerregistry;
import org.springframework.messaging.simp.stomp.stompcommand;
import org.springframework.messaging.simp.stomp.stompheaderaccessor;
import org.springframework.messaging.support.channelinterceptoradapter;
import org.springframework.messaging.support.messageheaderaccessor;
import org.springframework.web.socket.config.annotation.*;
@configuration
@enablewebsocketmessagebroker
@slf4j
public class websocketconfig extends abstractwebsocketmessagebrokerconfigurer {
//stomp监听类
@bean
public stompconnecteventlistener applicationstartlistener(){
return new stompconnecteventlistener();
}
@override
public void registerstompendpoints(stompendpointregistry stompendpointregistry) {
//建立连接端点,注册一个stomp的协议节点,并指定使用sockjs协议
stompendpointregistry.addendpoint("/nmpsocketweb")
.setallowedorigins("*")
.withsockjs();
}
@override
public void configuremessagebroker(messagebrokerregistry messagebrokerregistry) {
//配置消息代理(messagebroker)。
messagebrokerregistry.enablesimplebroker("/topic");// 推送消息前缀
messagebrokerregistry.setapplicationdestinationprefixes("/app");// 应用请求前缀,前端发过来的消息将会带有“/app”前缀。
}
@override
public void configureclientinboundchannel(channelregistration registration) {
//token认证
registration.setinterceptors(new channelinterceptoradapter() {
@override
public message<?> presend(message<?> message, messagechannel channel) {
stompheaderaccessor accessor = messageheaderaccessor.getaccessor(message, stompheaderaccessor.class);
if (stompcommand.connect.equals(accessor.getcommand()) || stompcommand.send.equals(accessor.getcommand())) {
string token = accessor.getfirstnativeheader("token");
try {
tokenvalidate(token);
} catch (exception e) {
log.error(e.tostring());
return null;
}
}
return message;
}
});
}
public boolean tokenvalidate(string token) throws exception {
if (token == null || token.isempty()) {
throw new exception("websocket:token为空!");
}
if (jwtutil.validatetoken(token)==null) {
throw new exception("websoc:token无效!");
}
return true;
}
}
代码中有详细的解释,认真看可以看明白的。
五、controller
import io.swagger.annotations.api;
import io.swagger.annotations.apioperation;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.messaging.messageheaders;
import org.springframework.messaging.handler.annotation.messagemapping;
import org.springframework.messaging.handler.annotation.sendto;
import org.springframework.messaging.simp.simpmessageheaderaccessor;
import org.springframework.messaging.simp.simpmessagetype;
import org.springframework.messaging.simp.simpmessagingtemplate;
import org.springframework.stereotype.controller;
import org.springframework.web.bind.annotation.requestmapping;
import org.springframework.web.bind.annotation.responsebody;
@api(tags="websocket控制器",description="websocket控制器")
@controller
@requestmapping(value = "/websocket")
public class websocketcontroller extends basecontroller {
@autowired
private simpmessagingtemplate simpmessagingtemplate;
@autowired
private redishelper redishelper;
@apioperation(value = "测试主动发送消息", notes = "测试主动发送消息", httpmethod = "get")
@requestmapping(value = "/sendmsg")
@responsebody
public void sendmsg(){
system.out.println("测试主动发送消息");
notifybean notifybean = notifybean.builder().message("服务器给你发消息啦!").build();
simpmessagingtemplate.convertandsend(webconstant.web_sc_topic_notify,notifybean);
}
@messagemapping("/test") //当浏览器向服务端发送请求时,通过@messagemapping映射/welcome这个地址,类似于@responsemapping
@sendto(webconstant.web_sc_topic_notify)//当服务器有消息时,会对订阅了@sendto中的路径的浏览器发送消息
public notifybean test(uservo uservo) {
try {
//睡眠1秒
thread.sleep(1000);
} catch (interruptedexception e) {
e.printstacktrace();
}
notifybean notifybean = notifybean.builder().message("welcome!"+ uservo.getname()).build();
return notifybean;
}
/**
* 点对点发送消息demo
* 根据用户key发送消息
* @param uservo
* @return
* @throws exception
*/
@messagemapping("/test/toone")
public void toone(uservo uservo) throws exception {
string sessionid=(string)redishelper.redistemplate.opsforvalue().get("websocket:"+uservo.getid());
notifybean notifybean = notifybean.builder().message("welcome!"+ uservo.getname()).build();
//convertandsendtouser该方法会在订阅路径前拼接"/user",所以前端订阅的路径全路径是"/user/topic/notify"
simpmessagingtemplate.convertandsendtouser(sessionid, webconstant.web_sc_topic_notify,notifybean,createheaders(sessionid));
}
private messageheaders createheaders(string sessionid) {
simpmessageheaderaccessor headeraccessor = simpmessageheaderaccessor.create(simpmessagetype.message);
headeraccessor.setsessionid(sessionid);
headeraccessor.setleavemutable(true);
return headeraccessor.getmessageheaders();
}
}
六、前端页面
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<link lang="en" xmlns:th="http://www.w3.org/1999/xhtml"></link>
<link href="/webjars/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"></link>
<head>
<script th:src="@{sockjs.min.js}"></script>
<script th:src="@{stomp.min.js}"></script>
<script th:src="@{jquery-1.11.3.min.js}"></script>
</head>
<body>
<blockquote class="layui-elem-quote">/user/topic-message</blockquote>
<div id="main-content" class="container">
<div class="row">
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="connect">websocket connection:</label>
<button id="connect" class="btn btn-default" type="submit">connect</button>
<button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">disconnect
</button>
</div>
</form>
</div>
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="name">what is your name?</label>
<input type="text" id="name" class="form-control" placeholder="your name here..."></input>
</div>
<button id="send" class="btn btn-default" type="submit">send</button>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table id="conversation" class="table table-striped">
<thead>
<tr>
<th>greetings</th>
</tr>
</thead>
<tbody id="greetings">
</tbody>
</table>
</div>
<div id="message"></div>
</div>
</div>
<script>
// /msg/sendcommuser
var stompclient = null;
//传递用户key值
var login = "ricky";
function setconnected(connected) {
$("#connect").prop("disabled", connected);
$("#disconnect").prop("disabled", !connected);
if (connected) {
$("#conversation").show();
}
else {
$("#conversation").hide();
}
$("#greetings").html("");
}
function connect() {
var socket = new sockjs('/nmpsocketweb');
stompclient = stomp.over(socket);
stompclient.connect({login:login}, function (frame) {
setconnected(true);
console.log('connected: ' + frame);
stompclient.subscribe('/user/topic/greetings', function (greeting) {
setmessageinnerhtml(json.parse(greeting.body).message);
console.log(json.parse(greeting.body).message)
});
});
}
function disconnect() {
if (stompclient != null) {
stompclient.disconnect();
}
setconnected(false);
console.log("disconnected");
}
function sendname() {
stompclient.send("/app/test/toone", {}, json.stringify({'name': $("#name").val(),'id':'ricky'}));
}
function showgreeting(message) {
$("#greetings").append("<tr><td>" + message + "</td></tr>");
}
$(function () {
$("form").on('submit', function (e) {
e.preventdefault();
});
$( "#connect" ).click(function() { connect(); });
$( "#disconnect" ).click(function() { disconnect(); });
$( "#send" ).click(function() { sendname(); });
});
//将消息显示在网页上
function setmessageinnerhtml(innerhtml){
console.log(innerhtml);
document.getelementbyid('message').innerhtml += innerhtml + '<br/>';
}
</script>
</body>
</html>
最好,来试试点对点推送。
第一个页面:
第二个页面:
可以看到,后台推送的消息只有一个页面接收到,完事!
下一篇: 干妈
推荐阅读
-
SpringBoot2.0集成WebSocket实现后台向前端推送信息
-
React Native集成阿里云推送----广播推送
-
spring boot项目中集成WebSocket,实现消息推送
-
Springboot+Netty+Websocket实现消息推送实例
-
springboot项目中使用netty+websocket 实现消息推送(带校验用户是否登陆功能)
-
springboot集成websocket点对点推送、广播推送
-
入门级 Springboot集成websocket通信 ,Scheduled定时推送
-
SpringBoot2.0整合WebSocket,实现后端数据实时推送!
-
SpringBoot+Netty+WebSocket,Channel和用户绑定关系,实现后台向前端推送信息
-
SpringBoot+webSocket+Vue设置后台向前端推送消息