Spring can't listen SessionDisconnectEvent - java

I made a demo referring to this project (websokets-spring),I mainly added WebSocketListener,this is my code
#Component
#Slf4j
public class WebSocketListener {
#EventListener
public void handleWebSocketConnectListener(SessionConnectEvent sessionConnectEvent) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionConnectEvent.getMessage());
log.debug("connect, sessionId = {}", headerAccessor.getSessionId());
}
#EventListener
public void handleWebSocketConnectedListener(SessionConnectedEvent sessionConnectedEvent) {
log.debug("connected ");
}
#EventListener
public void handleWebSocketDisconnectListener(SessionDisconnectEvent sessionDisconnectEvent) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionDisconnectEvent.getMessage());
log.debug("disconnect, session id = {}", sessionDisconnectEvent.getSessionId());
}
#EventListener
public void handleWebSocketSubscribeEvent(SessionSubscribeEvent sessionSubscribeEvent) {
log.debug("subscribe, {}", sessionSubscribeEvent.toString());
}
#EventListener
public void handleWebSocketUnsubscribeEvent(SessionUnsubscribeEvent sessionUnsubscribeEvent) {
log.debug("unsubscribe, {}", sessionUnsubscribeEvent.getSource());
}
}
When I enter the page to open the WebSocket connection and close the WebSocket connection or Close page, I can listen to the event。enter image description hereenter image description here
But when I use the front-end and back-end separated projects to connect WebSocket, I can listen to the SessionConnectEvent, but not the SessionDisconnectEvententer image description hereenter image description hereenter image description hereenter image description herethis is my front-end stomp code
function chatClient(): CompatClient {
const socket = SockJS('http://localhost/ws');
const client = Stomp.over(socket);
return client;
}
client = chatClient();
client.connect(
{
Authorization: getAuthorization(),
},
(frame: any) => {
console.log("ws success", frame);
client.subscribe(`/user/${userStore.userInfo.username}/messages`, function (message) {
console.log('msg', message.body);
});
}, (err: any) => {
console.log("ws err");
});

When using a proxy across domains, you need to enable websocket true
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
// rewrite: (path: string) => path.replace(/^\/api/, ""),
},
'/ws': {
target: 'http://localhost:8080',
changeOrigin: true,
ws: true
}
},
// port: 80,
open: false,
fs: {
strict: true,
},
}

Related

send event to java Socket IO from angular application

i want to send event to socket io server that ran on java spring boot application,
the weird point is that my angular app can connect to server perfectly and i can get connect and disconnect events in java.but when it comes to emit an event to server or get any event from server it is not working
Java Class:
public class SocketIOServerImpl {
public static void main(String[] args) throws InterruptedException {
Configuration config = new Configuration();
config.setHostname("localhost");
config.setPort(8090);
websocket
final SocketIOServer server = new SocketIOServer(config);
server.addConnectListener(socketIOClient -> {
System.out.println("User Connected");
server.getBroadcastOperations().sendEvent("daniyal", "You Connected to Server Successfully");
});
server.addDisconnectListener(client -> {
server.getBroadcastOperations().sendEvent("daniyal", "You Connected to Server Successfully");
});
server.addEventListener("daniyal", String.class, new DataListener<String>() {
#Override
public void onData(SocketIOClient socketIOClient, String s, AckRequest ackRequest) throws Exception {
System.out.println("User Connected");
server.getBroadcastOperations().sendEvent("daniyal", "You Emited STH to Server Successfully");
}
});
server.start();
Thread.sleep(Integer.MAX_VALUE);
server.stop();
}
}
angular servise.ts:
#Injectable({
providedIn: 'root'
})
export class SocketServiceService {
readonly uri: string = 'ws://localhost:8090';
socket: any;
constructor() {
this.socket = io.connect(this.uri,{ transports: [ 'websocket' ] });
}
listen(eventName: string) {
return new Observable((subscriber) => {
this.socket.on(eventName, (data: any) => {
subscriber.next(data);
});
});
}
emit(eventName: string, data: any) {
this.socket.emit(eventName, data);
}
}
app.component.ts:
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(private socketService: SocketServiceService) {
}
ngOnInit() {
this.socketService.listen('daniyal').subscribe(
(res) => {
console.log('Server Response: ',res);
});
}
emit(){
this.socketService.emit('daniyal','HI SERVER');
}
}
i use angular version 14 and java 11
i expected server can get the event and when send event to client,client get that too

Flutter websockets + Spring Boot chat application

I'm trying to setup connection between Flutter and Spring boot as backend using websocket, but I came across many problems. I found in the Internet many tutorials even on StackOverflow but still I can't correctly build my chat application.
I have been using this tutorial for backend: https://kiberstender.github.io/miscelaneous-spring-websocket-stomp-specific-user/
I just want to simple print the log on my backend service after incoming message, but I don't know what I'm doing wrong.
Flutter code:
try {
StompClient stompClient = StompClient(
config: StompConfig(
url: "ws://10.0.2.2:8080/websocket-chat",
onStompError: (StompFrame frame) {
print(
'A stomp error occurred in web socket connection :: ${frame.body}');
},
onWebSocketError: (dynamic frame) {
print(
'A Web socket error occurred in web socket connection :: ${frame.toString()}');
},
onDebugMessage: (dynamic frame) {
print(
'A debug error occurred in web socket connection :: ${frame.toString()}');
},
onConnect: (StompClient client, StompFrame connectFrame) {
print(
'${client.toString()} connected with the following frames ${connectFrame.body}');
_stompClient = client;
Map<String, String> asdf = {};
var clientUnSubscribeFn = _stompClient.subscribe(
destination: "ws://10.0.2.2:8080/user/queue/newMember",
headers: asdf,
callback: (frame) {
// Received a frame for this subscription
print("here" + frame.body);
});
},
),
);
stompClient.activate();
}
sendClientMessage(String msg) async {
Map<String, String> asdf = {};
var clientUnSubscribeFn = await _stompClient.subscribe(
destination: "ws://10.0.2.2:8080/topic/newMember",
headers: asdf,
callback: (frame) {
// Received a frame for this subscription
print("here" + frame.body);
});
_stompClient.send(
destination: "ws://10.0.2.2:8080/app/register",
body: "newUser\n",
headers: asdf);
clientUnSubscribeFn = await _stompClient.subscribe(
destination: "ws://10.0.2.2:8080/user/newUser/msg",
headers: asdf,
callback: (frame) {
// Received a frame for this subscription
print("here" + frame.body);
});
}
Backend code:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/user", "/topic", "/queue");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket-chat").setAllowedOrigins("*");
}
}
And the controller
#MessageMapping("/register") // 3
#SendToUser("/queue/newMember")
public Set<String> registerUser(String webChatUsername) {
logger.info(("reg"));
if (!connectedUsers.contains(webChatUsername)) {
connectedUsers.add(webChatUsername);
simpMessagingTemplate.convertAndSend("/topic/newMember", webChatUsername); // 4
logger.error(connectedUsers.toString());
return connectedUsers;
} else {
return new HashSet<>();
}
}
#MessageMapping("/unregister") // 5
#SendTo("/topic/disconnectedUser")
public String unregisterUser(String webChatUsername) {
logger.info(("unreg"));
connectedUsers.remove(webChatUsername);
return webChatUsername;
}
#MessageMapping("/message") // 6
public void greeting(WebSocketMessage message) {
logger.warn(("mes"));
simpMessagingTemplate.convertAndSendToUser(message.toWhom, "/msg", message);
In your backend code try this:
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket-chat").setAllowedOrigins("*");
registry.addEndpoint("/websocket-chat").setAllowedOrigins("*").withSockJS();
}
You don't need to supply the full URL again when subscribing/sending messages. So this:
var clientUnSubscribeFn = await _stompClient.subscribe(
destination: "ws://10.0.2.2:8080/topic/newMember",
headers: asdf,
callback: (frame) {
// Received a frame for this subscription
print("here" + frame.body);
});
_stompClient.send(
destination: "ws://10.0.2.2:8080/app/register",
body: "newUser\n",
headers: asdf);
should be
var clientUnSubscribeFn = await _stompClient.subscribe(
destination: "/topic/newMember",
headers: asdf,
callback: (frame) {
// Received a frame for this subscription
print("here" + frame.body);
});
_stompClient.send(
destination: "/app/register",
body: "newUser\n",
headers: asdf);

Some cookies are misusing the recommended “sameSite“ attribute

I'm building a react application that uses atmosphere library to listen to a SpringBoot websocket, when the client tries to connect to the server, it throws an error in the console saying Some cookies are misusing the recommended “sameSite“ attribute. I added some attributes to the request object to fix the issue as recommended (SameSite cookies). but I'm still getting the same error.
ReactJS code:
import React from 'react';
import * as atmosphere from 'atmosphere.js';
//import $ from 'jquery';
var transport = 'websocket';
//var req = new atmosphere.AtmosphereRequest();
// We are now ready to cut the request
var request = {
url:'http://localhost:8080/stream',
contentType: "application/json",
trackMessageLength: true,
shared: true,
enableXDR: true,
headers: { 'Access-Control-Allow-Origin': '*',
'sameSite': ' None; Secure'
},
//sameSite: 'None; Secure',
rewriteURL:true,
transport: transport,
fallbackTransport: 'long-polling',
onOpen: function(response:any) {
console.log('Atmosphere connected using ' , response.transport);
transport = response.transport;
},
onTransportFailure: function(errorMsg: Atmosphere.Response, request: Atmosphere.Request) {
console.log('Atmosphere Chat. Default transport is WebSocket, fallback is ' ,request.fallbackTransport );
},
onMessage: function (response:Atmosphere.Response) {
var message = response.responseBody;
try {
console.log('message: ', message);
} catch (e) {
console.log('This doesn\'t look like a valid JSON: ', message);
return;
}
},
onClose : function(response: Atmosphere.Response) {
console.log("Close connection !!!");
}
};
const socket = atmosphere;
// Connect to the server, hook up to the request handler.
console.log('socket : ', socket.subscribe);
socket.subscribe && socket.subscribe(request);
const AtmosphereWebSocket = () => {
return ( <div> </div> );
}
export default AtmosphereWebSocket;
SpringBoot Code:
#Component
#CrossOrigin(origins = "http://localhost:3000")
#WebSocketHandlerService(path = "/stream", broadcaster = SimpleBroadcaster.class,
atmosphereConfig = {"org.atmosphere.websocket.WebSocketProtocol=" +
"org.atmosphere.websocket.protocol.StreamingHttpProtocol"})
public class WebSocketStream extends WebSocketStreamingHandlerAdapter {
private final Logger logger = LoggerFactory.getLogger(WebSocketStream.class);
public WebSocketStream() {
System.out.println(" ** WebSocketStream ** ");
}
// A thread which sends a stream of data out of a websocket. Create when the class
// is instantiated, inject the websocket when open.
private class Stream extends Thread {
protected WebSocket socket;
protected final ObjectMapper mapper = new ObjectMapper();
protected boolean stop = false;
public Stream(WebSocket socket) {
this.socket = socket;
}
public void run() {
int count = 0;
try {
while (!stop) {
Map<String, Object> message = new HashMap<String, Object>();
message.put("time", new Date().toString());
message.put("count", count++);
String string = mapper.writeValueAsString(message);
socket.write(string);
System.out.println("tick: " + string);
Thread.sleep(1000);
}
} catch (Exception x) {
// break.
}
}
}
int clients = 0;
#Override
public void onOpen(WebSocket webSocket) throws IOException {
// Hook up the stream.
final Stream stream = new Stream(webSocket);
stream.start();
logger.info(" on open was called !!!");
webSocket.broadcast("client " + clients++ + " connected");
webSocket.resource().addEventListener(new WebSocketEventListenerAdapter() {
#Override
public void onDisconnect(AtmosphereResourceEvent event) {
if (event.isCancelled()) {
logger.info("Browser {} unexpectedly disconnected", event.getResource().uuid());
} else if (event.isClosedByClient()) {
logger.info("Browser {} closed the connection", event.getResource().uuid());
}
stream.stop = true;
}
});
}
}
Error Message:
Websocket failed on first connection attempt. Downgrading to long- polling and resending 1.chunk.js:3632:18
Atmosphere Chat. Default transport is WebSocket, fallback is long-polling atmosphere.tsx:27
The development server has disconnected.
Refresh the page if necessary. 1.chunk.js:7419:13
Sat Jul 11 2020 15:52:07 GMT-0500 (Central Daylight Time) Atmosphere: unload event 1.chunk.js:3632:18
[HMR] Waiting for update signal from WDS... log.js:24
Download the React DevTools for a better development experience: react-dom.development.js:24994
socket :
function subscribe(url, callback, request)
atmosphere.tsx:47
Firefox can’t establish a connection to the server at ws://localhost:8080/stream?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=3.0.5-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&Content-Type=application/json&X-atmo-protocol=true&Access-Control-Allow-Origin=*&sameSite=%20None%3B%20Secure. atmosphere.js:1201
Websocket closed, reason: Connection was closed abnormally (that is, with no close frame being sent). - wasClean: false atmosphere.js:3302
Close connection !!! atmosphere.tsx:40
Websocket failed on first connection attempt. Downgrading to long-polling and resending atmosphere.js:3302
Atmosphere Chat. Default transport is WebSocket, fallback is long-polling

Trying out Spring for JMS over WebSocket, have issues with controller

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;
}
}

atmoshphere one to one chat

I just started with Atmosphere for a simple chat application. I downloaded an example with java. This app is sending messages to all clients how can I send a message to a particular client. i think I am able to get uuid. Please someone guide me in right direction.
#Config
#ManagedService(path = "/chat", atmosphereConfig = MAX_INACTIVE + "=9990000")
public class Chat {
private final Logger logger = LoggerFactory.getLogger(Chat.class);
#Inject
private BroadcasterFactory factory;
#Heartbeat
public void onHeartbeat(final AtmosphereResourceEvent event) {
logger.trace("Heartbeat send by {}", event.getResource());
}
#Ready
public void onReady(final AtmosphereResource r) {
logger.info("Browser {} connected", r.uuid());
if(null!=factory && null!=factory.getClass()){
logger.info("BroadcasterFactory used {}", factory.getClass().getName());
}
}
#Disconnect
public void onDisconnect(AtmosphereResourceEvent event) {
if (event.isCancelled()) {
logger.info("Browser {} unexpectedly disconnected", event.getResource().uuid());
} else if (event.isClosedByClient()) {
logger.info("Browser {} closed the connection", event.getResource().uuid());
}
}
#org.atmosphere.config.service.Message(encoders = {JacksonEncoder.class}, decoders = {JacksonDecoder.class})
#DeliverTo(DeliverTo.DELIVER_TO.BROADCASTER)
public Message onMessage(Message message) throws IOException {
logger.info("{} just send {}", message.getAuthor(), message.getMessage());
return message;
}
}
Your Java class is incomplete.
Firstly, there is a missing variable which identify each chat room in your path :
#ManagedService(path = "/chat/{chatRoomId}", atmosphereConfig = MAX_INACTIVE + "=9990000")
public class Chat {
#PathParam("chatRoomId")
private String chatRoomId;
[...]
}
But, you can send all messages to only one socke connected.
Secondly, where is your script JS file to send and receive websocket message ?
This script JS file must contains these methods :
request.onOpen = function(request, response) {
};
request.onTransportFailure = function(request, response) {
};
request.onMessage = function(request, response) {
};
request.onClose = function(request, response) {
};
request.onError= function(request, response) {
};
request.onReconnect = function(request, response) {
};
The most important is to declare the structure of your request :
var socket = atmosphere;
var subSocket;
var transport = 'websocket';
var request = {
url: document.location.toString() + 'chat' + chatRoomId,
contentType : "application/json",
logLevel : 'debug',
transport : transport ,
trackMessageLength : true,
reconnectInterval : 5000
};

Categories

Resources