spring Sping Boot - WebSocket -不显示订阅者

yrdbyhpb  于 2022-12-26  发布在  Spring
关注(0)|答案(1)|浏览(182)

我正在复习基本的Sping Boot WebSocket教程:https://spring.io/guides/gs/messaging-stomp-websocket/
我决定修改它,打印出有多少用户订阅了控制台中的一个频道,但无法计算出几个小时。我已经看到了一些StackOverflow的帖子,但他们没有帮助。最后一个我检查是这样的:https://stackoverflow.com/a/51113021/11200149表示要添加,请尝试以下操作:

@Autowired private SimpUserRegistry simpUserRegistry;

public Set<SimpUser> getUsers() { 
    return simpUserRegistry.getUsers();
}

因此,我将以上内容添加到我的控制器中,更改如下:

@Controller
public class GreetingController {
    @Autowired
    private SimpUserRegistry userRegistry;

    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    public Greeting greeting(HelloMessage message) throws Exception {
        Set<SimpUser> subscribedUsers = userRegistry.getUsers();
        System.out.println("User amount: " + subscribedUsers.size()); // always prints: 0
        return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
    }
}

这将始终打印0:

System.out.println("User amount: " + subscribedUsers.size());

我来自Socket.IO,所以事情可能会有点不同,因为我看到人们实现了他们自己的手动订阅服务类。在www.example.com上socket.io,这将是小菜一碟,所以我假设Sping Boot 会有这个,但我似乎找不到它。

k5ifujac

k5ifujac1#

也许您可以尝试将自定义HandshakeHandler类添加到注册表中,并覆盖determineUser方法以返回包含订阅者名称的Principal对象,以便SimpUserRegistry可以正常工作。
如果你想看到的效果,下面是我正在尝试.

app.js(通过请求参数发送用户名)

function connect() {
    var socket = new SockJS('/gs-guide-websocket?name=' + $('#name').val());
    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);
        });
    });
}

自定义类扩展DefaultHandshakeHandler.class

@Component
public class WebSocketHandShakeHandler extends DefaultHandshakeHandler {

    @Override
    protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
        ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
        HttpServletRequest httpServletRequest = servletRequest.getServletRequest();
        String name = httpServletRequest.getParameter("name");

        return new MyPrincipal(name);
    }
}

自定义对象实现Principal.class

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MyPrincipal implements Principal {
    private String name;
}

Web套接字配置类

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Autowired
    private WebSocketHandShakeHandler webSocketHandShakeHandler;

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

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

显示所有订阅者

@RestController
public class ApiController {
    @Autowired
    private SimpUserRegistry simpUserRegistry;

    @GetMapping("/users")
    public List<String> connectedEquipments() {
        return this.simpUserRegistry
                .getUsers()
                .stream()
                .map(SimpUser::getName).toList();
    }
}

结果

顺便说一下,您可以检查DefaultSimpUserRegistry.class来观察将名称放入订阅者用户Map的过程。

相关问题