When a user goes to a specific end-point to find a stock-price, I want the stock price to update on the page every 3 seconds.
#Scheduled is not working on the following code:
#MessageMapping("/stocks/{name}")
#Scheduled(fixedRate = 3000)
public void stockData(#DestinationVariable String name) throws Exception {
Stock stock = YahooFinance.get(name);
simpMessagingTemplate.convertAndSend("/topic/stocks/" + name, stock);
}
JS front-end code:
var stompClient = null;
function connect(url) {
console.log("connect() called")
var socket = new SockJS('/stocks');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
console.log("connected")
setConnected(true);
stompClient.subscribe('/topic/stocks/' + url, function(
retrieveSingleStockData) {
console.log('retrieving...');
display(retrieveSingleStockData.body);
});
}, function(err) {
console.log(err);
});
}
The stomp-client can subscribe without any issues, but the method in the controller isn't sending back any data. I know it's an issue with the #Scheduled annotation.
I'd appreciate any help, thanks
Related
I want to initiate a trigger(maybe a notification) from backend(based in spring boot) to a particular user whose userId is xyz.
the one way i have found is:
initially i connect to a websocket end point and subscribe to channel "/user/Notifications/xyz"
following is the relevant code in my angular typescript
connectToUserWebSocket(userId) {
let socket = new SockJS('http://localhost:5000/fellowGenius');
this.ws = Stomp.over(socket);
let that = this;
this.ws.connect(
{},
(frame) => {
that.ws.subscribe('/user/Notifications/' +userId, (message) => {
console.log("user subscribed");
});
},
(error) => {
alert('STOMP error ' + error);
}
);
}
Now once i have subscribed to my channel . I want to send a trigger to client which is initiated by backend itself so i run a code in my java service.
My relevant java code is:
#SendTo("/user/Notifications/{userId}")
public String sendMeetingNotificationWebSocket(#DestinationVariable String userId) {
return "hello";
}
my websocket configurations are:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/fellowGenius").setAllowedOrigins("*").addInterceptors(new HttpSessionHandshakeInterceptor()).withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/inbox/","/user/Notifications/");
}
}
But the problem is that even i can see one web socket connected in my spring boot console.
But i don't get a response from the function on the client side.
Please help me with this problem.
If i execute following code, sha.getLogin() and sha.getPasscode() outputs null !?
What is wrong with the code?
Client:
var socket = new SockJS('/ws');
stompClient = Stomp.over(socket);
stompClient.connect("123","456", function (frame) {
//...
});
Server:
#EventListener
private void onSessionConnect(SessionConnectedEvent event)
{
StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
System.out.println(sha.getLogin());
System.out.println(sha.getPasscode());
}
But if execute following command, the login and passcode is contained.
sha.getMessageHeaders().toString()
Output (no json):
{
simpMessageType=CONNECT_ACK,
simpConnectMessage=GenericMessage[
payload=byte[0],
headers={
simpMessageType=CONNECT,
stompCommand=CONNECT,
nativeHeaders={
login=[123],//<<<Login
passcode=[PROTECTED],//<<<Passcode
accept-version=[
1.1,
1.0
],
heart-beat=[
10000,
10000
]
},
simpSessionAttributes={},
simpHeartbeat=[J#4b5cea63,
stompCredentials=[PROTECTED],
simpSessionId=xhojby2n
}
],
simpSessionId=xhojby2n
}
You can use accessor.getPasscode() method instead of accessor.getFirstNativeHeader(PASSWORD_HEADER)
bacause default StompDecoder protect passcode when setting
public void setPasscode(#Nullable String passcode) {
setNativeHeader(STOMP_PASSCODE_HEADER, passcode);
protectPasscode();
}
private void protectPasscode() {
String value = getFirstNativeHeader(STOMP_PASSCODE_HEADER);
if (value != null && !"PROTECTED".equals(value)) {
setHeader(CREDENTIALS_HEADER, new StompPasscode(value));
setNativeHeader(STOMP_PASSCODE_HEADER, "PROTECTED");
}
}
Spring is accessing the session data when you call sha.getLogin() or sha.getPasscode() but your user isn't authenticated on session, when you send connect ACK you need to intercept the message and authenticate user on the session.
Take a look at Spring Security WebSocket Support & Sessions
I'm trying to make a connection between client and server via Spring webSocket and I'm doing this by the help of this link.
I want Controller to send a "hello" to client every 5 seconds and client append it to the greeting box every time.
This is the controller class:
#EnableScheduling
#Controller
public class GreetingController {
#Scheduled(fixedRate = 5000)
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public Greeting greeting() throws Exception {
Thread.sleep(1000); // simulated delay
System.out.println("scheduled");
return new Greeting("Hello");
}
}
and This is Connect() function in app.jsp:
function connect() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.send("/app/hello", {}, JSON.stringify({'name': "connect"}));
stompClient.subscribe('/topic/greetings', function (message) {
console.log("message"+message);
console.log("message"+(JSON.parse(message.body)));
showGreeting(JSON.parse(message.body).content);
});
});
}
when the index.jsp loads and I press the connect button, only one time it appnds hello in greeting, how should I make client to show "hello" message every 5 seconds?
Please reffer to this portion of the documentation.
The way you are trying to send a message is totally wrong.
I would modify your above class as follows:
#EnableScheduling
#Controller
public class GreetingController {
#Autowired
private SimpMessagingTemplate template;
#Scheduled(fixedRate = 5000)
public void greeting() {
Thread.sleep(1000); // simulated delay
System.out.println("scheduled");
this.template.convertAndSend("/topic/greetings", "Hello");
}
}
I tried to implement this example https://spring.io/guides/gs/messaging-stomp-websocket/ and it all worked fine. So i moved forward and tried to make it work with a standalone HornetQ.
So, i defined a topic in HornetQ config - /topic/requests
Here are the changes i've made
In index.html i got rid of sockJS
function connect() {
var ws = 'ws://127.0.0.1:61613/stomp';
stompClient = Stomp.client(ws);
stompClient.connect("guest", "guest", function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('jms.topic.requests', function(greeting){
showGreeting(JSON.parse(greeting.body).content);
});
});
}
Sending message from browser
function sendName() {
var name = document.getElementById('name').value;
stompClient.send("jms.topic.requests", {}, JSON.stringify({ 'name': name }));
}
ShowGreeting
function showGreeting(message) {
var response = document.getElementById('response');
console.log('response: ' + response);
var p = document.createElement('p');
p.style.wordWrap = 'break-word';
p.appendChild(document.createTextNode(message));
response.appendChild(p);
}
Configured Spring to work with a standalone broker
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp");
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic", "/queue");
//registry.setApplicationDestinationPrefixes("/jms");
}
Controller
#MessageMapping("/stomp")
#SendTo("/topic/requests")
public Greeting greeting(HelloMessage message) throws Exception {
System.out.println("Controller called!");
Thread.sleep(3000); // simulated delay
return new Greeting("Hello, " + message.getName() + "!");
}
As a result, it can connect to a running instance of hornetQ and send messages to a topic. However, instead of printing specified string back it just prints "undefined". I know that message is reaching the queue, as i have another browser-based subscriber.
That println in controller is never called, so i suspect i've failed to properly configure it, but i have no idea what would it be.
Greeting
public class Greeting {
private String content;
public Greeting(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
Im trying to use the Channel API of Google App Engine.
JavaScript / JQuery:
$(document).ready(function(){
alert('ready');
$.post('/token', function(data) {
alert('token:' + data['token']);
openChannel( data['token'] );
});
$.post('/chat', function(data) {
alert('chat:' + data['users'].length);
});
});
onMessage = function(message) {
alert(message);
}
onSocketError = function(error){
alert("Error is <br/>"+error.description+" <br /> and HTML code"+error.code);
};
onSocketOpen = function() {
// socket opened
};
onSocketClose = function() {
alert("Socket Connection closed");
};
openChannel = function(token) {
alert('open channel');
var channel = new goog.appengine.Channel( token );
var socket = channel.open();
socket.onopen = onSocketOpen;
socket.onmessage = onMessage;
socket.onerror = onSocketError;
socket.onclose = onSocketClose;
};
The problem is that alert(message) doesn't fire. What is lucking in my code?
Im confused on some of the examples having "\\{\\{ token \\}\\}" in server side and channel = new goog.appengine.Channel('{{ token }}') in javascript.
What is it enclosed in {{ }}?
Please note token is a TOKEN KEY which identifies your page. Initialize token in page first like:
ChannelService channelService = ChannelServiceFactory.getChannelService();
String token = channelService.createChannel("sample");
Now
var token ="<%=token %>";// This will creaete unique identifier(some id created by google api + ur key)
channel = new goog.appengine.Channel('<%=token%>');
socket = channel.open();
socket.onopen = function () {
var connected = true;
sendMessage('<b>'+userName+'</b> Logged in.');
};
.. Create functions like this
Besides using the correct token, your onMessage function doesn't fire because that will happen when you send a message from the server to the client:
channelService.sendMessage(new ChannelMessage(channelKey, "Hello World"));
you can set up a XMLHttpRequest in order to communicate from the client to the server side, where the java code before can be run, for example:
sendMessage = function(path, param) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'path + '&' + param', true);
xhr.send();
};
in javascript
function onMessage(msg)
{
var msg1=msg.data;
$('textarea').val($('textarea').val()+msg1);
}
in backend
ChannelService channelService = ChannelServiceFactory.getChannelService();
channelService.sendMessage(new ChannelMessage(clientid,message));