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));
}

Возможно, есть лучший способ сделать это, и я с интересом посмотрю на этот вопрос, но я нашел подход, который сработал.

Другие вопросы по тегам