我在 Spring Boot 中有一个简单的服务器。我想实现并测试我的 Web 套接字连接,但如果我想订阅端点“/topic/resources”,超时将在 30 秒后超时。消息发送正确,控制器中的函数callFunction()被调用。你知道为什么它不起作用吗?
控制器:
@Controller
public class WebSocketController {
@MessageMapping("/{classType}/{functionName}")
@SendTo("/topic/resources")
public String callFunction(
@DestinationVariable String classType,
@DestinationVariable String functionName,
Optional<Map<String, Object>> params
) {
return classType + " " + functionName;
}
}
配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/management").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/call");
registry.enableSimpleBroker("/topic");
}
}
测试:
@SpringBootTest(classes = ManagementFrameworkApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WebSocketTest {
private CompletableFuture<String> completableFuture = new CompletableFuture<>();
@LocalServerPort
private int port;
private final ObjectMapper objectMapper = new ObjectMapper();
@Test
public void testCreateGameEndpoint() throws InterruptedException, ExecutionException, TimeoutException {
WebSocketStompClient stompClient = new WebSocketStompClient(new SockJsClient(createTransportClient()));
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
StompSession stompSession = stompClient.connect("ws://localhost:" + port + "/management", new StompSessionHandlerAdapter() {})
.get(5, SECONDS);
final var params = objectMapper.createObjectNode();
params.set("numbers", objectMapper.createArrayNode().add(1).addNull().add(2));
params.put("operator", Operator.ADD.name());
stompSession.subscribe("/topic/resources", new StringStompFrameHandler());
stompSession.send("/call/CalculatorMResource/sum", params);
String string = completableFuture.get(30, SECONDS); // here is Timeout!
System.out.println(string);
}
private List<Transport> createTransportClient() {
List<Transport> transports = new ArrayList<>(1);
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
return transports;
}
private class StringStompFrameHandler implements StompFrameHandler {
@Override
public Type getPayloadType(StompHeaders stompHeaders) {
return String.class;
}
@Override
public void handleFrame(StompHeaders stompHeaders, Object o) {
completableFuture.complete((String) o);
}
}
}
问题在于您的测试中缺少
StringMessageConverter
的 WebSocketStompClient
注册。您的 websocket 端点返回一个纯字符串,MappingJackson2MessageConverter
无法转换该字符串,因为此转换器仅负责 application/json
。
试试这个:
WebSocketStompClient stompClient = new WebSocketStompClient(new SockJsClient(createTransportClient()));
stompClient.setMessageConverter(new StringMessageConverter());