How to communicate with spring websocket - javascript

I am trying to build an application where the server will keep pushing message to the client in some interval.
I have a simple html file like this.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="sockjs/sockjs.js"></script>
<script src="stomp/stomp.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<button ng-click='connect()'>hi</button>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.connect = function() {
var socket = new SockJS('http://localhost:8099/myws');
$scope.stompClient = Stomp.over(socket);
$scope.stompClient.connect({}, function (frame) {
console.log('Connected:bhabani ' + frame);
$scope.stompClient.subscribe('http://localhost:8099/topic/jobconfig', function (wsdata) {
console.log("helloooooooooooooooooooooooooooooooooooooooooooooooooo");
console.log(wsdata);
});
});
}
});
</script>
I opened the html file in the file system.
file:///export/data1/test-ws.html in the browser.
Now i have a spring web socket like this.
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Autowired
private GreetingController gc;
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/myws").setAllowedOrigins("*").withSockJS();
new Thread(gc).start();
}
}
Have a greeting controller like this, which should push a message to the topic in some internal
#Component
public class GreetingController implements Runnable{
#Autowired
private SimpMessagingTemplate template;
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while(true){
try {
System.out.println("Sending");
Thread.sleep(1000);
template.convertAndSend("/topic/jobconfig", new Greeting("hi"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
Where i press the connect button i can see connection is established.
But after that i do not see any message coming in the browser which should be pushed from the server.
I am expecting the 'helloooooooooooo' message should be printed in my browser console in each interval.

Change URL in stomp client subscribe code from this http://localhost:8099/topic/jobconfig to this /topic/jobconfig.
$scope.stompClient.subscribe('/topic/jobconfig', function(wsdata) {
console.log("hello");
console.log(wsdata);
});

Related

Spring Boot Websocket with SockJS and StompJS connect function does not work, always error

I try to build a chat application with HTML,JS,CSS with the libraries STOMPJS and SOCKJS as the frontend and Spring Boot as backend.
My connect code in the frontend looks like this:
function connect() {
var socket = new SockJS("http://localhost:8080/chat");
stompClient = Stomp.over(socket);
stompClient.connect(
{},
function (frame) {
console.log("2");
setConnected(true);
console.log("Connected: " + frame);
stompClient.subscribe("/topic/messages", function (messageOutput) {
showMessageOutput(JSON.parse(messageOutput.body));
});
},
console.log("error")
);
}
As far as I know is the connect function of STOMPJS like this: headers, connectCallback, errorCallback.
It never reach the console.log "2" and it gives me the console.log "error" back.
I activated CORS like this in my backend with setAllowedOriginPatterns("*") in my Spring Boot application:
#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("/chat");
registry.addEndpoint("/chat").setAllowedOriginPatterns("*").withSockJS();
}
}
And the controller looks like this:
#Controller
public class MController {
#MessageMapping("/chat")
#SendTo("/topic/messages")
public OutputMessage send(Message message) throws Exception {
String time = new SimpleDateFormat("HH:mm").format(new Date());
return new OutputMessage(message.getFrom(), message.getText(), time);
}
}
In the screenshot you can see the console.log when I execute the function "connect":
I checked all the documentation of SockJS and StompJS but I couldn't find a solution.
Thank you very much for your answer in advance. :)

Events not being sent to JavaScript

I am using react-native to develop an android app. I am using native code to run a service in the foreground. This service consists of collections the accelerometer sensor readings of the phone.
Starting the service returns a successful promise but I do not receive no events. The following is the implementation of the service class:
public class PhonePositionService extends Service {
public static final String FOREGROUND = "com.testnative.position.FOREGROUND";
...
//Event listener for sensors -start
SensorEventListener sensorEventListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent event) {
PhonePositionService.this.sendMessage(event);
}
...
};
//Event Listener - end
#Override
#TargetApi(Build.VERSION_CODES.M)
public void onCreate() {
sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE); //get services provided by sensor manager
mAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //specifiy sensor
sensorManager.registerListener(sensorEventListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); //register it
}
private void sendMessage(SensorEvent event) {
try {
float[] values = event.values;
Intent intent = new Intent("PhonePosUpdate");
intent.putExtra("message", values);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
...
The thing is not even a notification appears, I'm afraid the service didnt start at all.
The Following is my Module which uses this service:
public class PhonePositionModule extends ReactContextBaseJavaModule {
public PhonePositionModule(ReactApplicationContext reactContext) {
super(reactContext);
BroadcastReceiver phonePositionReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
float[] message = intent.getFloatArrayExtra("message");
PhonePositionModule.this.sendEvent(message);
}
};
LocalBroadcastManager.getInstance(getReactApplicationContext()).registerReceiver(phonePositionReceiver, new IntentFilter("PhonePosUpdate"));
}
...
#ReactMethod
public void startService(Promise promise) {
String result = "Success";
try {
Intent intent = new Intent(PhonePositionService.FOREGROUND); ///////
intent.setClass(this.getReactApplicationContext(), PhonePositionService.class);
getReactApplicationContext().startService(intent);
} catch (Exception e) {
promise.reject(e);
return;
}
promise.resolve(result);
}
...
private void sendEvent(float[] message) {
WritableMap map = Arguments.createMap();
map.putDouble("x", message[0]);
map.putDouble("y", message[1]);
map.putDouble("z", message[2]);
getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("updatePosition", map);
}
}
When I call startService() from JavaScript, I get a success. However no notification appears and
DeviceEventEmitter.addListener('updatePosition', (Data) => {
console.log(Data);
in App.js shows nothing.
Thus:
1) The Notification does not appear
2) Given that the notification does not appear, the service did not start (even though the promise did not return an error).
I tried debugging the native code on Android Studio but logcat isn't working for me.

SignalR methods in WebApi controller not called in specific setup

Well, I have a signalR hub:
public class ReportHub : Hub
{
private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<ReportHub>();
public void SendMessage(string text)
{
Clients.All.sendMessage(text);
}
public static void ServerSendMessage(string text)
{
hubContext.Clients.All.sendMessage(text);
}
}
Also I have the client code in js, on some view
report.client.sendMessage = message => {
alert('message from server: '+ message);
}
And I have webapi action, like this:
[HttpGet]
[Route("api/Report/test")]
public int GetTest()
{
ReportHub.ServerSendMessage("message");
return 42;
}
When I open the view with signalR-catching js code in one browser, and in another browser window requesting the webapi action, by typing http://../api/report/test - all working, and alert is appearing
But when I calling webapi action via postman, or any other rest client, no effect at all, report.client.sendMessage = message => {
alert('message from server: '+ message);
} - not working
Can anyone help?
ReportHub.ServerSendMessage("message");
It is wrong.
You should return ReportHubContext for the connection before pushing the data to clients;
[HttpGet]
[Route("api/Report/test")]
public int GetTest()
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ReportHub>();
hubContext.ServerSendMessage("message");
return 42;
}

JavaScript client cannot connect to Spring 4 WebSocket

I have implemented websocket in spring but the JavaScript client cannot connect to the websocket.
Here is the WebSocketConfig class:
package com.myapp.spring.security.config;
import com.myapp.spring.web.controller.MyWebSocketHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
//import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.handler.PerConnectionWebSocketHandler;
#Configuration
#EnableWebMvc
#EnableWebSocket
#ComponentScan(basePackages={"com.myapp.spring.*"})
public class WebSocketConfig implements WebSocketConfigurer {
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry
.addHandler(myWebSocketHandler(), "/endpoint")
.setAllowedOrigins("*");
}
#Bean
public WebSocketHandler myWebSocketHandler() {
return new PerConnectionWebSocketHandler(MyWebSocketHandler.class);
}
}
Here is the test.html page that tries to connect to the websocket:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<body>
<p>Going to connect to the WebSocket at /endpoint. Check Console</p>
<button onclick="ss()">Send</button>
</body>
<script type="text/javascript">
var webSocket = new WebSocket("wss://"+document.location.hostname+":8443"+"/endpoint");
webSocket.onopen = function(message) {
processOpen(message);
};
webSocket.onmessage = function(message) {
processMessage(message);
};
webSocket.onclose = function(message) {
processClose(message);
};
webSocket.onerror = function(message) {
processError(message);
};
function processOpen(message) {
console.log("JS: Server Connected... "+message);
}
function processMessage(message) {
console.log("Getting a mess: "+message);
}
function processClose(message) {
console.log("JS: Client disconnected... "+message);
}
function processError(message) { //
console.log("Error occured: "+message);
}
function ss() {
webSocket.send("test");
}
</script>
</html>
I initialized the websocket path to be at /endpoint. This is evident by my server logs which say that this has occurred:
[org.springframework.web.socket.server.support.WebSocketHandlerMapping] (ServerService Thread Pool -- 75) Mapped URL path [/endpoint] onto handler of type [class org.springframework.web.socket.server.support.WebSocketHttpRequestHandler]
When I open up test.html, the connection opens and immediately disconnects. The processOpen(message) and processClose(message) function are immediately called, one after the other. So what am I doing wrong, and how can I fix this?
Your java-script code in test.html looks fine. There could be some issue with Spring Web socket configuration which is closing the connection. Following is the working code for web socket with spring boot. Please compare with your configuration.
Web socket dependency in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocketHandler class
#Component
public class EchoHandler extends TextWebSocketHandler {
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
TextMessage echoMessage = new TextMessage("Echo :" + message.getPayload());
System.out.println("Sending "+echoMessage.getPayload());
session.sendMessage(echoMessage);
}
}
WebSocket Controller class
#EnableWebSocket
#Controller
public class WSController implements WebSocketConfigurer {
#Autowired
private EchoHandler echoHandler;
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(echoHandler, "/echo").setAllowedOrigins("*");
}
}
Spring Boot application class
#SpringBootApplication
public class WSApplication {
public static void main(String[] args) {
SpringApplication.run(WSApplication.class, args);
}
}

SignalR Get Clients outside of Hub not working

I am trying to call signalR from a controller, but it doesnt work.
Controller:
public ActionResult Index(){
var hub = GlobalHost.ConnectionManager.GetHubContext<ClientControl>();
hub.Clients.All.sendMessage("ahahhaaa");
//... return and staff
}
Hub
[Authorize]
[HubName("userTracking")]
public class ClientControl : Hub
{
public void RegisterConnection(String controller, String action)
{
}
public override Task OnConnected()
{
}
public override Task OnDisconnected()
{
return base.OnDisconnected();
}
}
Frontend:
$(document).ready(function () {
var trackhub = $.connection.userTracking;
trackhub.client.sendMessage = function (msg) {
alert(msg);
}
$.connection.hub.logging = true;
$.connection.hub.start();
});
In the controller it doesnt throw an error. When I debug and pause it, hub object exists, but when I perform it, it sends no message to the frontend. If I call the same method from the hub - works as a charm.
Any idea, what can be the root cause of the problem? If needed - write in the comments I will provide more info.
Server
public class ChatHub : Hub
{
public int TryAddNewUser(string userName)
{
//some logic...
Clients.All.AddUserToUserList(id, userName);
return id;
}
public void AddNewMessageToPage(int id, string message)
{
//some logic...
Clients.All.addNewMessageToPage(u.Login, message);
}
}
Client
$(document).ready(function () {
//first need register client methods
var chat = $.connection.chatHub;
chat.client.addUserToUserList = function (id, login) {
//client logic for add new user
}
chat.client.addNewMessageToPage = function (login, message) {
//client logic for add new message from user
}
//second need start chat
$.connection.hub.start().done(function () {
chat.server.tryAddNewUser(login).done(function (id) {
alert("Added " + id)
});
});
});
Controller
public class ChatController : Controller
{
private IMyDataService _service;
public ChatController(IMyDataService s)
{
_service = s;
}
public ActionResult Index()
{
return View(new MyDataViewModel(_service));
}
}
Note, dynamic js file must be added with the same path
<script type="text/javascript" src="~/signalr/hubs"></script>
And i add following code to Startup.cs
using Owin;
using Microsoft.Owin;
[assembly: OwinStartup(typeof(ChatRoom.Startup))]
namespace ChatRoom
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
}
}
}
About this see link
Please change the hub name in controller to work
Use
var hub = GlobalHost.ConnectionManager.GetHubContext<UserTracking>();
hub.Clients.All.sendMessage("ahahhaaa");
Instead of
var hub = GlobalHost.ConnectionManager.GetHubContext<ClientControl>();
hub.Clients.All.sendMessage("ahahhaaa");
Please note the change in Hub Class Name in GetHubContext<>.
Hope this helps.

Categories

Resources