SpringBoot получает InputStream и OutputStream из веб-сокета
Мы хотим интегрировать стороннюю библиотеку (Eclipse XText LSP) в наше веб-приложение SpringBoot.
Эта библиотека работает "интерактивно" с пользователем (например, в чате). Для работы XText API требуется поток ввода и вывода. Мы хотим использовать WebSocket, чтобы позволить пользователям беспрепятственно взаимодействовать с этой библиотекой (отправлять / получать сообщения json).
У нас проблема с SpringBoot, потому что поддержка SpringBoot для WebSocket не предоставляет потоки ввода / вывода. Мы написали пользовательский TextWebSocketHandler (подкласс), но ни один из его методов не обеспечивает доступ к входящим / выходным потокам.
Мы также пытались использовать HandshakeInterceptor (для получения входных / выходных потоков после рукопожатия), но безуспешно.
Можем ли мы использовать SpringBoot WebSocket API в этом сценарии или мы должны использовать какой-нибудь API более низкого уровня (Servlet?)?
С уважением, Даниэль
1 ответ
Я не уверен, подойдет ли это вашей архитектуре или нет, но я достиг этого, используя поддержку STOMP в Spring Boot и встроив ее в пользовательский интерфейс. org.eclipse.lsp4j.jsonrpc.RemoteEndpoint
вместо использования более низкого уровня API.
Подход был вдохновлен чтением кода, представленного в org.eclipse.lsp4j.launch.LSPLauncher
,
Обработчик JSON
Маршаллинг и демаршаллинг JSON должны выполняться с помощью API, предоставляемого языковым сервером xtext, а не Джексона (который будет использоваться при интеграции Spring STOMP)
Map<String, JsonRpcMethod> supportedMethods = new LinkedHashMap<String, JsonRpcMethod>();
supportedMethods.putAll(ServiceEndpoints.getSupportedMethods(LanguageClient.class));
supportedMethods.putAll(languageServer.supportedMethods());
jsonHandler = new MessageJsonHandler(supportedMethods);
jsonHandler.setMethodProvider(remoteEndpoint);
Ответ / уведомления
Ответы и уведомления отправляются получателем сообщения, который передается remoteEndpoint
когда построено. Сообщение должно быть отправлено jsonHandler
чтобы Джексон не делал это.
remoteEndpoint = new RemoteEndpoint(new MessageConsumer() {
@Override
public void consume(Message message) {
simpMessagingTemplate.convertAndSendToUser('user', '/lang/message',
jsonHandler.serialize(message));
}
}, ServiceEndpoints.toEndpoint(languageServer));
Запросы
Запросы могут быть получены с помощью @MessageMapping
метод, который занимает все @Payload
как String
чтобы Джексон не разоблачил это. Затем вы можете разобрать себя и передать сообщение remoteEndpoint
,
@MessageMapping("/lang/message")
public void incoming(@Payload String message) {
remoteEndpoint.consume(jsonHandler.parseMessage(message));
}
Возможно, есть лучший способ сделать это, и я с интересом посмотрю на этот вопрос, но я нашел подход, который сработал.