I want to send notification to all client connected using websocket and webstomp ,so I need to push notification when some row added to database , I tried something like this but did not work
my socket configuration
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/socket")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
controller
template.convertAndSend("/topic/notification", position);
front
methods: {
connect() {
this.socket = new SockJS("http://localhost:8082/socket");
this.stompClient = Stomp.over(this.socket);
this.stompClient.connect({},
frame => {
this.connected = true;
console.log(frame);
this.stompClient.subscribe("/topic/notification", tick => {
console.log(tick);
this.$notify({
group: 'foo',
title: '<h4>Nothing!</h4>',
text: 'car added',
type: 'success',
duration: 1000
})
});
},
error => {
console.log(error);
this.connected = false;
}
);
},
},
Related
Controller
#RestController
#RequestMapping
#CrossOrigin(origins = "*")
public class ProductController {
#Autowired
private ProductService productService;
#SendTo("/topic/all")
public List<Product> findAll() {
return productService.findAll();
}
}
WebSocketConfig
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("http://127.0.0.1:5500").withSockJS();
}
Js Code
function connect() {
let stompClient = null;
let socket = new SockJS('http://localhost:8080/ws');
stompClient = Stomp.over(socket);
stompClient.connect({}, (frame) => {
stompClient.subscribe('/topic/all',(response) => {
console.log(JSON.parse(response))
console.log(true)
});
});
}
connect();
hello, this is my small project, my main goal in this project is to show all the products in real time, because when a new product is added by the admin, the same product should be visible to the user. I am using debug stompclient.subscribe not wokring Please help me Thanks
I configured socket in my spring boot + angularjs application and you can see configuration classes here:
WebSocketBrokerConfig
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketBrokerConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry
.addEndpoint("/looping")
.withSockJS()
.setClientLibraryUrl("https://cdn.jsdelivr.net/sockjs/1.1.2/sockjs.min.js");
}
}
WebSocketSecurityConfig
#Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages.anyMessage().authenticated();
}
#Override
protected boolean sameOriginDisabled() {
return true;
}
}
WebSocketAuthenticationConfig
#Configuration
#EnableWebSocketMessageBroker
#Order(Ordered.HIGHEST_PRECEDENCE + 99)
public class WebSocketAuthenticationConfig implements WebSocketMessageBrokerConfigurer {
private static final Logger logger = LoggerFactory.getLogger(WebSocketAuthenticationConfig.class);
#Autowired
private TokenProvider tokenProvider;
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Autowired
private IUserService iUserService;
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
#Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
String jwt = getJwtFromRequest(accessor);
logger.debug("X-Authorization: {}", jwt);
Long userId = tokenProvider.getUserIdFromToken(jwt);
User user = iUserService.loadById(userId);
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, authorities);
accessor.setUser(authentication);
}
return message;
}
});
}
private String getJwtFromRequest(StompHeaderAccessor accessor) {
String bearerToken = accessor.getFirstNativeHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
}
and this is client side:
function SocketController($timeout, localStorageService) {
var vm = this;
var accessToken = localStorageService.get('accessToken');
var stompClient;
console.log(accessToken)
if (accessToken) {
stompClient = webstomp.over(new WebSocket('ws://localhost:8000/looping'));
stompClient.connect({"Authorization": "Bearer " + accessToken}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/loops', function (message) {
console.log(message);
});
});
} else {
console.log("token expired");
}
}
In this case i see this below error in firefox devtools:
I also tried with SockJS as you can see below:
function SocketController($timeout, localStorageService) {
var vm = this;
var accessToken = localStorageService.get('accessToken');
var stompClient;
console.log(accessToken)
if (accessToken) {
var socket = new SockJS('https://localhost:8000/looping');
stompClient = Stomp.over(socket);
stompClient.connect({"Authorization": "Bearer " + accessToken}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/loops', function (message) {
console.log(message);
});
});
} else {
console.log("token expired");
}
}
And with SockJS i get 401 error when var socket = new SockJS('https://localhost:8000/looping'); is called.
NOTE
I using token oauth2 authorization and need to send token when handshaking for socket.
I have a problem with a configuration of a WebSocket using Spring and SockJs.
I have configured all my app like Spring Documentation, the connection seems to be fine, but when I send a message the Controller is never involved and it doesn't work.
This is the Configuration component:
#Configuration
#EnableWebMvc
#EnableWebSocketMessageBroker
public class MyWebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer implements WebSocketConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/mySocket").withSockJS().setInterceptors(new MySocketHandshakeInterceptor());;
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app").enableSimpleBroker("/topic");
}
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
}
}
This is the HandshakeInterceptor implementation:
public class MySocketHandshakeInterceptor implements HandshakeInterceptor {
#Override
public void afterHandshake(ServerHttpRequest paramServerHttpRequest, ServerHttpResponse paramServerHttpResponse, WebSocketHandler paramWebSocketHandler, Exception paramException) {
// TODO Auto-generated method stub
System.out.println("MySocketHandshakeInterceptor afterHandshake");
}
#Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> paramMap)
throws Exception {
System.out.println("MySocketHandshakeInterceptor beforeHandshake");
return true;
}
}
This is the Controller component:
#Controller
public class MySocketController {
#MessageMapping("/testsocket")
#SendTo("/topic/testresponse")
public MessageOut test(MessageIn message) throws Exception {
System.out.println("MySocketController start");
System.out.println("MySocketController test "+ message);
return new MessageOut("test OK");
}
}
These are MessageIn and MessageOut:
public class MessageIn {
private String test;
/**
* #return the test
*/
public String getTest() {
return test;
}
}
public class MessageOut {
private String result;
public MessageOut(String result) {
super();
this.result = result;
}
/**
* #return the test
*/
public String getResult() {
return result;
}
/**
* #param result the result to set
*/
public void setResult(String result) {
this.result = result;
}
}
Finally, this is the client side (javascript):
var socketSession = {};
connectToMySocket();
function connectToVideoSocket() {
socketSession.socket = new SockJS("/mySocket");
socketSession.socket.stomp = Stomp.over(socketSession.socket);
socketSession.socket.stomp.debug = null;
socketSession.socket.stomp.connect({}, function () {
socketSession.socket.stomp.subscribe("/topic/testresponse", function (data) {
console.log(data);
});
});
}
This is the command that I launch to test the socket:
socketSession.socket.stomp.send("app/testsocket", {}, JSON.stringify({'test': 'test'}));
In the system out console I can only see the two rows:
MySocketHandshakeInterceptor beforeHandshake
MySocketHandshakeInterceptor afterHandshake
The interceptor works fine, but I don't see any print by the Controller component.
What's wrong?
Thanks.
I resolved by myself.
It was a problem of the client-side.
The correct script is:
var mySocket = undefined;
var stompClient = undefined;
connectToVideoSocket();
function connectToVideoSocket() {
mySocket = new SockJS('/mySocket');
stompClient = Stomp.over(mySocket);
stompClient.debug = null;
stompClient.connect({}, function(frame) {
stompClient.subscribe('/topic/testresponse', function(data){
console.log(JSON.parse(data.body).result);
});
});
}
In this way it works fine.
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")
Afternoon everyone. I'm having an issue with sockjs and Spring4. I don't know which side of the setup is causing the issue. The problem is I can't seem to get IE8 to open a connection to my Spring backend over HTTPS.
I'm trying to implament this example: https://demo.rasc.ch/spring4ws/
The link I'm trying is the chat.
The link to his source is here: https://github.com/ralscha/spring4ws-demos
The only change I made to his source is I'm using jquery-1.9.1 , Spring 4.0.0, and the full stomp.js and not the stomp.min.js
The sock and stomp code in the index page for the chat client is:
$(function() {
var username, lastUsername, stompClient, content = $("#content")[0],
input = $("#editor input")[0];
function notify(text) {
$('<p class="message notice"/>').text(text).appendTo(content);
content.scrollTop = content.scrollHeight;
}
$(input).keyup(function(event) {
if (event.which === 13 && $.trim(input.value)) {
if (!username) {
username = input.value;
$("#editor p").addClass("user").removeClass("guide").text(username);
var path = window.location.pathname.substring(0,
window.location.pathname.lastIndexOf('/')+1);
var sock = new SockJS(path + 'chat');
stompClient = Stomp.over(sock);
stompClient.connect({}, function(frame) {
notify("The connection has been opened");
$(input).removeAttr("disabled").focus();
stompClient.subscribe("/queue/chatmessage", function(msg) {
var data = JSON.parse(msg.body);
if (lastUsername !== data.username) {
lastUsername = data.username;
$('<p class="user"/>').text(data.username).appendTo(content);
}
$('<p class="message"/>').text(data.message).appendTo(content);
content.scrollTop = content.scrollHeight;
});
},
function(error) {
notify("An error occured: " + error);
$(input).attr("disabled", "disabled");
});
} else {
stompClient.send("/queue/chatmessage", {}, JSON.stringify({username: username, message: input.value}));
}
input.value = "";
}
});
$(input).focus();
$(window).resize(function() {
$(content).height($(window).height() - $("#editor").outerHeight(true) - 15).scrollTop(content.scrollHeight);
}).resize();
});
Sorry about the formatting.
In Spring all I did was separate the the webconfig java file into 2 files
WebConfig is standard. Extends WebMvcConfigurerAdapter :
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index.html");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
WebSocket implaments WebSocketMessageBrokerConfigurer:
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").withSockJS().setSessionCookieNeeded(false);
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue/");
}
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
// use default thread pool with 1 thread
}
#Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(2).maxPoolSize(3);
}
The initilizer is basic too.
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class, WebSocketConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/chatdemo/*" };
}
I'm also running this through Tomcat 7 using eclipse. So not the embedded tomcat.
The problem I'm having is the readystate inside sock is being set to permanent in IE. I don't fully understand xhr/xdr polling, but I'm assuming that's the problem.
Is there anything else I need to do to get IE to work over https on the sockjs side or the spring side?