I am learning Spring WebSocket. I have successfully run this Spring WebSocket tutorial. Now I am trying to incorporate it as-is in my existing Spring MVC application. When I run it from Chrome browser, I see below error in its dev console.
Chrome Console
Opening Web Socket...
GET http://localhost:8080/MyAppName/api/gs-guide-websocket/info?t=1497735312528 500 (Internal Server Error) -- abstract-xhr.js:132
Whoops! Lost connection to http://localhost:8080/MyAppName/api/gs-guide-websocket -- stomp.min.js:8
Server Side Error
javax.servlet.ServletException: Could not resolve view with name '/MyAppName/api/gs-guide-websocket/info' in servlet with name 'MyAppName'
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1262)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037)
Client Side
function connect() {
var socket = new SockJS('/MyAppName/api/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
}
Server Side
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/MyAppName/api/gs-guide-websocket").withSockJS();
}
}
I have tried to solve this for couple hours now. How do I resolve this?
ty
If your application context is MyAppName then you don't need to specify it in the addEndpoint method - this path is relative to your aaplication context.
Probably registry.addEndpoint("/MyAppName/api/gs-guide-websocket") registers the endpoint with path /MyAppName/MyAppName/api/gs-guide-websocket
Perhaps, mine example will hint the problem
My application base URL
http://localhost:8080/socket/
My js file
function connect() {
var socket = new SockJS('/socket/greeting');
stompClient = Stomp.over(socket);
stompClient.connect({name: 'test'}, function(frame) {
console.log("session Id:" + socket._transport.url);
console.log("user Id:" + socket.current_user_id);
console.log("socket Id:" + stompClient.id);
var sessionId = /\/([^\/]+)\/websocket/.exec(socket._transport.url)[1];
$("#fname").val(sessionId);
console.log("socket Id:" + sessionId);
stompClient.subscribe("/user/queue/errors", function(message) {
alert("Error " + message.body);
});
stompClient.subscribe("/user/queue/reply", function(message) {
showGreeting(message.body);
});
}, function(error) {
alert("STOMP error " + error);
});
}
My socket configuration
package com.connectips.socket.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import com.connectips.socket.interceptor.HttpHandshakeInterceptor;
#Configuration
#EnableWebSocketMessageBroker
public class SocketConfig implements WebSocketMessageBrokerConfigurer{
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic/", "/queue/");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/greeting").addInterceptors(new HttpHandshakeInterceptor()).withSockJS();
}
}
Related
I am using jHipster to build my backend java app with kwycloak oauth2 authentication, and now, and I want to add websocket support with stomp client.
What I did is add WebsocketConfiguration.java file:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfiguration implements WebSocketMessageBrokerConfigurer
{
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/queue");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/tracker")
.setAllowedOriginPatterns("*")
.withSockJS();
registry.addEndpoint("/stock-ticks").setAllowedOriginPatterns("*").withSockJS();
registry.addEndpoint("/stock-ticks").setAllowedOriginPatterns("*");
}
}
and in frontend js file I would like to call:
function connect() {
let socket = new SockJS('/stock-ticks');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
stompClient.subscribe('/topic/ticks', function (ticks) {
...
});
});
}
However, it always return 1006 error.
I tried the same thing using this Baeldung Example, it works fine without any issue.
Is there any configuration I missed? I am confused
I'm trying to build a chat using SpringBoot and websockets. When I try to connect to the controller I get a 404 in the debugger. What am I doing wrong?
main.js
function connect(event) {
username = document.querySelector('#name').value.trim();
if (username) {
usernamePage.classList.add('hidden');
chatPage.classList.remove('hidden');
var socket = new SockJS('http://localhost:8080/ws');
stompClient = Stomp.over(socket);
stompClient.connect({}, onConnected, onError);
}
event.preventDefault();
}
WebSocketConfig.java
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
}
}
Hi all I trying to connect to STOMP end point in Spring boot app and getting this error when ever I connect to it using STOMP.js and sock.js
o.s.w.s.m.StompSubProtocolHandler : Failed to parse TextMessage payload=[CONNECT
ac..], byteCount=523, last=true] in session b9ql5g3w. Sending STOMP ERROR to client.
org.springframework.messaging.simp.stomp.StompConversionException: Illegal header: ' setConnected(true);'. A header must be of the form <name>:[<value>].
at org.springframework.messaging.simp.stomp.StompDecoder.readHeaders(StompDecoder.java:224) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.messaging.simp.stomp.StompDecoder.decodeMessage(StompDecoder.java:138) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.messaging.simp.stomp.StompDecoder.decode(StompDecoder.java:111) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.messaging.simp.stomp.BufferingStompDecoder.decode(BufferingStompDecoder.java:133) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageFromClient(StompSubProtocolHandler.java:234) ~[spring-websocket-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:307) [spring-websocket-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.socket.handler.WebSocketHandlerDecorator.handleMessage(WebSocketHandlerDecorator.java:75) [spring-websocket-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.handleMessage(LoggingWebSocketHandlerDecorator.java:56) [spring-websocket-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.handleMessage(ExceptionWebSocketHandlerDecorator.java:58) [spring-websocket-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.delegateMessages(AbstractSockJsSession.java:385) [spring-websocket-4.2.5.RELEASE.jar:4.2.5.RELEASE]
at ..............................................................
and my javascipt code is
function connect() {
var socket = new SockJS('/hello');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/Presence', function(greeting){
console.log(greeting.body);
showGreeting(JSON.parse(greeting.body).userId,JSON.parse(greeting.body).status,JSON.parse(greeting.body).imageUrl);
});
});
}
I am also using spring boot security. and my Websocket Config and endpont are
#MessageMapping("/hello")
#SendTo("/topic/Presence")
public UserPresences greeting(String message) throws Exception {
Thread.sleep(1000); // simulated delay
return new UserPresences();
}
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello").withSockJS();
}
}
I was able to solve my problem by changing code on the client side
function connect() {
var socket = new SockJS('/hello');
stompClient = Stomp.over(socket);
stompClient.connect('','', function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/Presence', function(greeting){
console.log(greeting.body);
showGreeting(JSON.parse(greeting.body).userId,JSON.parse(greeting.body).status,JSON.parse(greeting.body).imageUrl);
});
});
}
Is it possible to use stomp over sockjs without MVC. So I would like to have spring rest interface in tomcat, and angular2 application run by express.
WebSocketConfig.java
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// the endpoint for websocket connections
registry.addEndpoint("/portfolio").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/app");
config.enableSimpleBroker("/topic");
}
}
SocketController.java
#Controller
public class SocketController {
#Autowired
private SimpMessagingTemplate template;
public SocketController() {
int a = 5;
}
#MessageMapping("/greeting")
public String handle(String greeting) {
return "[" + "greeting" + ": " + greeting;
}
}
and typescript code:
.
.
.
constructor() {
var socket = new SockJS('http://localhost:8080/portfolio');
this.stompClient = Stomp.over(socket);
this.stompClient.connect("guest", "guest", function(frame) {
console.log('Connected: ' + frame);
this.stompClient.subscribe('http://localhost:8080/topic/greeting', function(greeting) {
console.log("from from", greeting);
});
}, function (err) {
console.log('err', err);
});
}
.
.
.
send() {
this.stompClient.send("http://localhost:8080/app/greeting", {}, JSON.stringify({ 'name': "kitica" }));
}
.
.
.
but for some reason this is not working.. in console I get output:
Opening Web Socket...
stomp.js:134 Web Socket Opened...
stomp.js:134 >>> CONNECT
login:guest
passcode:guest
accept-version:1.1,1.0
heart-beat:10000,10000
stomp.js:134 <<< CONNECTED
version:1.1
heart-beat:0,0
stomp.js:134 connected to server undefined
activity-socket.ts:17 Connected: CONNECTED
heart-beat:0,0
version:1.1
and when I send I get
>>> SEND
destination:http://localhost:8080/app/greeting
content-length:17
{"name":"kitica"}
but message never comes back to subscriber.
angular2 is on port 8001 and spring rest is on 8080
The part that was confusing is that I am using spring-boot-rest and I am not serving angular2 as static from tomcat container, I have angular2 under webpack so I was constantly trying to subscribe and send to relative URL.
The right way to do is:
import {Component} from '#angular/core';
import {ActivityService} from '../common/services';
import {MaterializeDirective} from 'angular2-materialize';
import {LarsActionButtonComponent} from '../common/components';
var SockJS = require('sockjs-client');
var Stomp = require('stompjs');
#Component({
selector: 'activity',
providers: [ActivityService],
directives: [MaterializeDirective, LarsActionButtonComponent],
templateUrl: 'app/activity/activity.html'
})
export class Activity {
stompClient: any;
activityId: any;
text: any;
messages: Array<String> = new Array<String>();
constructor() {
}
send() {
this.stompClient.send('/app/hello/' + this.activityId, {}, JSON.stringify({ 'name': this.text }));
}
connect() {
var that = this;
var socket = new SockJS('tst-rest.mypageexample/hello?activityId=' + this.activityId);
this.stompClient = Stomp.over(socket);
this.stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
that.stompClient.subscribe('/topic/greetings/' + that.activityId, function (greeting) {
that.messages.push(JSON.parse(greeting.body).content);
});
}, function (err) {
console.log('err', err);
});
}
}
and in spring controller:
#Controller
public class SocketController {
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
return new Greeting("Hello, " + message.getName() + "!");
}
}
Configuration class:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello").setAllowedOrigins("*").withSockJS();
}
}
i had myself some issues to work with an angular2 client using stomp over SockJs versus a Java spring-boot back-end. Here what i did to make it working:
On the angular side:
this.stompClient.subscribe cannot be find, so bind "this" to "that".
constructor() {
var that = this;
var socket = new SockJS('http://localhost:8080/portfolio');
this.stompClient = Stomp.over(socket);
this.stompClient.connect("guest", "guest", function(frame) {
console.log('Connected: ' + frame);
that.stompClient.subscribe('http://localhost:8080/topic/greeting', function(greeting) {
console.log("from from", greeting);
});
}, function (err) {
console.log('err', err);
});
}
On the Java server side:
Your Controller need an annotation that said where the vallue is returned like this:
#MessageMapping("/greeting")
#SendTo("/topic/greetings")
public String handle(String greeting) {
return "[" + "greeting" + ": " + greeting;
}
According to your message broker.
Hope that's help a bit.
You have send the 'handle()' method value to the subscriber
either using
simpMessagingTemplate.convertAndSend(, );
e.g.- simpMessagingTemplate.convertAndSend("/topic/chats", message.getMessage());
or
#SendTo("destination url") above the handler method.
e.g.- #SendTo("/topic/message")
so I'm trying to send messages back to my browser from the server and have two methods that are supposed to be wired to send the messages to the STOMP topic.
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public static Greeting greeting(HelloMessage message) throws Exception {
System.out.println("Sending message...");
Application.startBody(message.getName());
return new Greeting("Hello, " + message.getName() + "!");
}
#SendTo("/topic/greetings")
public static Greeting security(String message) {
System.out.println("entered the informer");
return new Greeting("bye, " + message + "!");
}
The first one is also mapped to receive messages and send one back. The first funciton works and the message makes it back to the browser and displays on the webpage. The second once however, does not work. It never displays a received message in the console of the web page. Can I only send to the same topic with one method? I tried changing the topic and adding a subscription to my Stomp client but that didn't work either. Does it have anything to do with the second method being static? (I need to call it from a separate class.)
This is my subscription in the html file:
function connect() {
var socket = new SockJS("http://localhost:8080/hello");
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function(greeting){
showGreeting(JSON.parse(greeting.body).content);
});
});
}
And here is my WebSocketConfig.java:
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/app").enableSimpleBroker("/queue","/topic");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/hello").withSockJS();
}
}
I have the same problem and reading the WebShocket Support of Spring it's said:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html
STOMP servers can use the MESSAGE command to broadcast messages to all subscribers.
It’s important to know that a server cannot send unsolicited messages.*
All messages from a server must be in response to a specific client subscription and the "subscription-id" header of the server message must match the "id" header of the client subscription.
So I guess that the first method works because it's a response form the previous mapping.
Ok, I solved this problem with The SimpMessageSendingOperations
#Controller
public class PrincipalController {
private static SimpMessageSendingOperations messagingTemplate;
#Autowired
public PrincipalController(SimpMessageSendingOperations messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
...
public static void security(String message){
System.out.println("entered the informer");
PrincipalController.messagingTemplate.convertAndSend("/topic/greetings", new Greeting("bye, " + message + "!"));
}
}
...
#Theo - from another class
just autowire this service
#Service
public class MessageService {
#Autowired
public SimpMessageSendingOperations messagingTemplate;
public void sendMessage( String message ) {
messagingTemplate.convertAndSend( "/topic/greetings", new Greeting( "bye, " + message + "!" ) );
}
}