这是关于使用 websocket + stompjs 发送推送通知的spring 启动 + angularjs Web应用程序。
我最近从Spring Boot 1.2.0升级到2.1.3 。 之前,此升级网络套接字(推送通知)可以正常工作几年。
我刚刚升级了Spring Boot,并且与Websocket相关的代码仍然完全相同,但是现在不正在工作。
不起作用表示:
simpMessagingTemplate.convertAndSend("/topic/notify", payload);
我不知道,因为
代码(但相同的代码在Spring boot 1.2.0中也能很好地工作:
1。配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Value("${server.sessionTimeout}")
long sessionTimeoutInSecs;
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/notify").withSockJS();
}
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
// in milliseconds
container.setMaxSessionIdleTimeout(sessionTimeoutInSecs * 1000);
return container;
}
}
2。邮件发送代码:
simpMessagingTemplate.convertAndSend("/topic/notify", payload);
3。客户代码:
(function() {
myApp.factory('autoUpdateTasksService', function($resource, $q, $log) {
var initSockets, notify, reconnect, socket, _callback;
_callback = null;
socket = {
client: null,
stomp: null
};
initSockets = function() {
socket.client = new SockJS('/notify');
socket.stomp = Stomp.over(socket.client);
socket.stomp.connect({}, function() {});
socket.client.onopen = function() {
var subscription1;
subscription1 = socket.stomp.subscribe("/topic/notify", notify);
//$log.log('socket connected');
};
};
reconnect = function() {
setTimeout(initSockets, 1000);
};
notify = function(message) {
try{
var taskNotifyObject;
if (message.body) {
taskNotifyObject = angular.fromJson(message.body);
//$log.log(taskNotifyObject);
var notificationArray=[];
notificationArray.push(taskNotifyObject);
_callback(notificationArray);
} else {
//$log.log("empty message");
}
} catch(e){
// alert(e.message);
}
};
return {
init: function(callback) {
_callback = callback;
initSockets();
}
};
});
}).call(this);
Spring框架之间的版本之间有什么变化吗?
如何调试/查找丢失消息的位置?
答案 0 :(得分:0)
根本原因::升级后,我问题中的代码无法在服务器和客户端之间建立连接(未能创建 websocketSession )
更改代码,可以解决以下问题,但我不确定为什么该解决方案有效,
如果有人解释为什么,该解决方案有效,将会有很大帮助。
1。配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Value("${server.servlet.session.timeout}")
long sessionTimeoutInSecs;
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/notify").addInterceptors(new HttpSessionHandshakeInterceptor());
}
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
// in milliseconds
container.setMaxSessionIdleTimeout(sessionTimeoutInSecs * 1000);
return container;
}
/**
* DefaultSimpUserRegistry is the replacement of MySessionRegistry ( Custom UserSessionRegistry ) after upgrade to Spring 5.
* Below required with Spring 4.
* import org.springframework.messaging.simp.user.UserSessionRegistry;
@Repository
public class MySessionRegistry implements UserSessionRegistry, ApplicationListener<AbstractSubProtocolEvent> {
*
*/
@Bean
public DefaultSimpUserRegistry defaultSimpUserRegistry() {
DefaultSimpUserRegistry userRegistry = new DefaultSimpUserRegistry();
return userRegistry;
}
}
2。邮件发送代码:
import org.springframework.web.socket.messaging.DefaultSimpUserRegistry;
@Autowired
DefaultSimpUserRegistry defaultSimpUserRegistry;
.....
SimpUser simpUser = defaultSimpUserRegistry.getUser(payload.getUserName());
if(simpUser != null && simpUser.hasSessions()) {
template.convertAndSendToUser(payload.getUserName(), "/queue/notify", payload);
}
3。客户代码:
(function() {
myApp.factory('autoUpdateTasksService', function($resource, $q, $log) {
var initSockets, notify, reconnect, socket, _callback;
_callback = null;
socket = {
client: null,
stomp: null
};
getContextPath = function() {
return window.location.pathname.substring(0, window.location.pathname.indexOf("/",2));
};
initSockets = function() {
//socket.addr = "wss://" + window.location.host + "/notify";
socket.addr = ((window.location.protocol && (window.location.protocol.indexOf("https") >= 0)) ? "wss://" : "ws://") + window.location.host + getContextPath() + "/notify";
socket.client = Stomp.client(socket.addr); //new SockJS('/notify');
socket.client.connect({}, function () {
$log.log("Connected to websocket through " + socket.addr);
socket.client.subscribe("/user/queue/notify", notify);
}, function (err) {
$log.log("Error when connection to websocket " + socket.addr + ".\n" + err);
});
};
如何调试/查找消息丢失的地方?
要验证客户端与服务器的连接(或创建websocketSession),我在监听器下面添加了内容。
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.web.socket.messaging.SessionConnectedEvent;
import org.springframework.web.socket.messaging.SessionSubscribeEvent;
@Component
public class WebSocketListener implements ApplicationListener <ApplicationEvent> {
//WebSocket session created
if (appEvent instanceof SessionConnectedEvent){
StompHeaderAccessor sha = StompHeaderAccessor.wrap(((SessionConnectedEvent) appEvent).getMessage());
logger.info("SessionConnectedEvent: STOMP WebSocket session created for the user: {}", sha.getUser().getName());
}
//subscribed to websocketSession
if (appEvent instanceof SessionSubscribeEvent){
StompHeaderAccessor sha = StompHeaderAccessor.wrap(((SessionSubscribeEvent) appEvent).getMessage());
logger.info("SessionSubscribeEvent: User {} subscribed to WebSocket session, destination: {}", sha.getUser().getName(), sha.getDestination());
}
//
// if (appEvent instanceof BrokerAvailabilityEvent){
// logger.info("BrokerAvailabilityEvent: {}", appEvent.toString());
// }
}
}