2

I have following code on server side:

@Autowired
private SimpMessagingTemplate simpMessagingTemplate;

@MessageMapping("/hello")
public void greeting(@Payload HelloMessage message, Principal principal) throws Exception {
    Thread.sleep(1000); // simulated delay
    simpMessagingTemplate.convertAndSendToUser(principal.getName(), "/topic/greetings", new Greeting("Ololo"));        
}

client side code:

function connect() {
    var socket = new SockJS('/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);
        });
    });
}
function showGreeting(message) {
    $("#greetings").append("<tr><td>" + message + "</td></tr>");
}

My actions:

I run application, log in as user1 and initiate message sending from client to server and I see that method greeting is invokes and line simpMessagingTemplate.convertAndSendToUser(principal.getName(), "/topic/greetings", new Greeting("Ololo")) executes successfully but I don't see that message on the client side.

How can I

more sources:

spring security configuration:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String SECURE_ADMIN_PASSWORD = "rockandroll";

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .formLogin()
                .loginPage("/index.html")
                    .loginProcessingUrl("/login")
                    .defaultSuccessUrl("/sender.html")
                    .permitAll()
                .and()
                .logout()
                    .logoutSuccessUrl("/index.html")
                    .permitAll()
                .and()
                .authorizeRequests()
                .antMatchers("/js/**", "/lib/**", "/images/**", "/css/**", "/index.html", "/","/*.css","/webjars/**", "/*.js").permitAll()
                .antMatchers("/websocket").hasRole("ADMIN")
                .requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN")
                .anyRequest().authenticated();

    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

        auth.authenticationProvider(new AuthenticationProvider() {

            @Override
            public boolean supports(Class<?> authentication) {
                return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
            }

            @Override
            public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;

                List<GrantedAuthority> authorities = SECURE_ADMIN_PASSWORD.equals(token.getCredentials()) ?
                        AuthorityUtils.createAuthorityList("ROLE_ADMIN") : null;

                return new UsernamePasswordAuthenticationToken(token.getName(), token.getCredentials(), authorities);
            }
        });
    }
}

web socket config:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/gs-guide-websocket").withSockJS();
    }

}

update

After advices and reading topic Sending message to specific user on Spring Websocket I tried following:

1.

server side:

simpMessagingTemplate.convertAndSendToUser("user1", "/queue/greetings", new Greeting("Ololo"));

client side:

stompClient.subscribe('/user1/queue/greetings', function(menuItem){
    alert(menuItem);
});

2.

server side:

simpMessagingTemplate.convertAndSendToUser("user1", "/queue/greetings", new Greeting("Ololo"));

client side:

stompClient.subscribe('/user/queue/greetings', function(menuItem){
    alert(menuItem);
});

3.

server side:

simpMessagingTemplate.convertAndSendToUser("user1", "/queue/greetings", new Greeting("Ololo"));

client side:

stompClient.subscribe('user/user1/queue/greetings', function(menuItem){
    alert(menuItem);
});

It doesn't work anyway

gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • Do you see on the developer console of your browser (a) "Connected: ..." on opening the application in your browser , (b) "... Ololo .." after server sends its message? If you see the initial "Connected", but not the "Ololo", then you may not subscribe to the correct target. Should the target not start with "/user" instead of "topic"? – Markus Pscheidt Apr 26 '18 at 14:30
  • @Markus Pscheidt subscription in browser happens successfully - I checked it. I modified code a bit https://github.com/gredwhite/demo_ws_app/blob/master/src/main/java/hello/GreetingController.java and it sends message only **Hello ...** – gstackoverflow Apr 26 '18 at 14:36
  • @Markus Pscheidt should I subscribe on user specific queue sepratedly? – gstackoverflow Apr 26 '18 at 14:39
  • You receive "Hello.." because the client subscribed to `/topic/greetings` and `@SendTo("/topic/greetings") public Greeting greeting(...)` delivers a message to this queue. You might have success in subscribing to `/user/user1/topic/greetings`, because that's where `simpMessagingTemplate.convertAndSendToUser(principal.getName(), "/topic/greetings", new Greeting("Ololo"))` seems to deliver to. – Markus Pscheidt Apr 26 '18 at 14:46
  • @Markus Pscheidt, I tried several combination but I was not successful. Can you provide exact answer? – gstackoverflow Apr 26 '18 at 15:35
  • **client side log:** >>> SUBSCRIBE id:sub-1 destination:/user/user1/topic/greetings **server side code:** simpMessagingTemplate.convertAndSend("/user/" + principal.getName() + "/topic/greetings", new Greeting("Ololo")); – gstackoverflow Apr 26 '18 at 15:44
  • 2018-04-26 18:49:12.077 DEBUG 7908 --- [nboundChannel-5] o.s.m.s.b.SimpleBrokerMessageHandler : Processing SUBSCRIBE /topic/greetings id=sub-0 session=nhqik0nz – gstackoverflow Apr 26 '18 at 15:51
  • 2018-04-26 18:49:20.225 DEBUG 7908 --- [nboundChannel-3] o.s.m.s.b.SimpleBrokerMessageHandler : Processing MESSAGE destination=/topic/greetings-usernhqik0nz session=null payload={"content":"Ololo"} 2018-04-26 18:49:20.232 DEBUG 7908 --- [nboundChannel-3] o.s.m.s.b.SimpleBrokerMessageHandler : Processing MESSAGE destination=/topic/greetings session=nhqik0nz payload={"content":"Hello, vasya!"} – gstackoverflow Apr 26 '18 at 15:51
  • You might need to add "queue" to the simple broker: config.enableSimpleBroker("/topic" , "/queue"); – Markus Pscheidt Apr 26 '18 at 16:11
  • 1
    @Markus Pscheidt, I did it. Can you look at https://github.com/gredwhite/demo_ws_app/tree/master/src ? – gstackoverflow Apr 26 '18 at 16:16

2 Answers2

2

Only necessary change is on the client (app.js): Instead of /user/user1/queue/greetings, subscribe to /user/queue/greetings:

stompClient.subscribe('/user/queue/greetings', ...

Then login as user1 in the web interface. It has to be user1 because that's the user that is targeted at the server:

convertAndSendToUser("user1", "/queue/greetings", new Greeting("Ololo")) 

Upon clicking Send, The Ololo message appears as a client alert.

Markus Pscheidt
  • 6,853
  • 5
  • 55
  • 76
  • So "user1" would be the username returned by userservice.loadUserByUsername right in Spring, right? Would it be possible to do something like this: When there is an update to a child, get the usernames of the parents of that child, and run convertAndSendToUser(username, /queue/updates ... ) for each parents username. – Jordan Mackie Jul 11 '18 at 14:29
  • 1
    You are free to send a message to any user, so why not sending to the users that happen to be the parents of a specific child. When a parent is logged in, he/she receives the message – Markus Pscheidt Jul 12 '18 at 12:35
  • thanks! And just while I've got your attention, I can use a similar approach with convertAndSend("any/topic/at/all", message) to send a message from anywhere in the application (services etc) to subscribers of topic/any/topic/at/all, yeah? ( I'm thinking how to update subscribers if a resource is changed through a REST call rather than through the messagemapper method.) – Jordan Mackie Jul 12 '18 at 12:40
  • 1
    That's right, sending messages from anywhere in the system, including services, is possible, as long as the messaging template is available. – Markus Pscheidt Jul 12 '18 at 18:46
1

it works with me now under

template.convertAndSendToUser("username","/queue/notification",notifications); //server

stompClient.subscribe('/user/username/queue/notification', ....  // client

thanks every body

Ahmed Shalash
  • 133
  • 1
  • 1
  • 12