Рубрики
Без рубрики

Простой веб-сайт между Java и React (с крючками)

Асинхронная связь: призрачная угроза, когда вы работаете инженером-программистом или разработчиком… С тегами java, react, websocket, крючки.

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

Веб-сайты: новая надежда

Во время моего текущего проекта мы (я и моя команда) столкнулись со следующей проблемой: после определенного действия пользователя приложение должно предотвращать все остальные действия и ждать OK / KO с сервера. Было неизвестно, сколько времени может потребоваться серверу для отправки ответа, но требование было ясным: независимо от того, сколько времени пользователь должен дождаться ответа или позвонить в службу поддержки клиентов, если он считает, что это займет много времени. После небольшого обсуждения мы решили попробовать реализовать веб-сайт, чтобы позволить клиенту ждать сообщения (даже вечно, если это необходимо).

Что такое веб-карман?

Я не хочу беспокоить вас информацией, которую вы можете получить самостоятельно из более авторитетных источников. Проще говоря, Websocket – это протокол, который обеспечивает полнодуплексную связь по протоколу TCP, позволяя как клиенту, так и серверу отправлять/получать сообщения друг от друга и управлять событиями на основе полученного сообщения.

Теперь внешний интерфейс – это чисто React + машинопись, в то время как внутренний интерфейс написан на Java в рамках OSGi, поэтому невозможно использовать простые решения, такие как socket.io это позволяет deleoper использовать одну и ту же технологию как на FE, так и на BE.

Давайте кодировать вместе – Интерфейс

Поскольку я отвечал за переднюю часть, я сначала опишу свой код реакции. Еще одним требованием, которое следует иметь в виду, было то, что веб-сайт открывается при запуске приложения. Поэтому я решил использовать ref крюк для управления объектом WebSocket и проверки, закрыт он или открыт, и логическое значение Должно быть сохранено , чтобы включить/отключить функцию, которая поддерживает соединение во время ожидания ответа:

  const connection = useRef();
  const shouldKeepWSAlive = useRef(false);

После этого нам нужно узнать, какое событие запускает веб-сайт. Теперь у меня была эта переменная под названием ждет ли что-то , что отвечает за блокировку приложения, как сказано до поэтому я решил использовать использовать эффект хук для управления открытием веб-сайта ( что такое эффект использования? )

useEffect(() => {
    if (!(connection && 
        connection.current && 
        connection.current.readyState === 1))
    {
      connection.current = new WebSocket("ws://path-to-websocket");
      connection.current.onopen = () => {
          //do something, maybe just log that the websocket is open;
      }
      connection.current.onclose = () => {
          //do something, maybe just log that the websocket is closed;
      };
      connection.current.onmessage = (e) => {
        aFunction();
      };
    }
  }, [dependencies]);

Просто небольшое объяснение:

  • оператор if вверху помогает мне проверить, открыто ли уже соединение;
  • если соединение не открыто, код блокируется внутри, если открыть новое соединение;
  • onopen и onclose – это события по умолчанию, которые запускаются при запуске и закрытии соединения;
  • onmessage – важная часть: это событие, которое запускается при получении сообщения на интерфейсе;
  • функция() – это моя пользовательская функция, которая выполняет логику, которую я хочу;
  • с правильными зависимостями Websocket открывается при запуске приложения;
  • поскольку даже у Websocket есть тайм-аут, вам может потребоваться снова открыть его.

Однако, если серверу требуется много времени для отправки сообщения, во время ожидания Websocket может истечь время ожидания и закрыться, поэтому я добавил простую функцию keepAlive() таким образом:

  const keepAlive = useCallback(() => {
    if (shouldKeepWSAlive.current) {
      if (connection.current !== undefined && 
          connection.current !== null &&
          connection.current.readyState === 1) 
      {
        connection.current.send("");
      }
      setTimeout(() => {
        keepAlive();
      }, 20000);
    }
  }, []);

  useEffect(() => {
    if (isWaitingVendi) {
      shouldKeepWSAlive.current = true;
      keepAlive();
    } else {
      shouldKeepWSAlive.current = false;
    }
  }, [isWaitingVendi, keepAlive]);

После этого мой веб-сайт работал и работал хорошо.

Давайте кодировать вместе – Бэкэнд

В этом разделе я кратко опишу Java-часть Websocket. BE управлялся другим членом команды, поэтому я не буду вставлять подробные объяснения, но я попросил его написать специальный пост.

Мы разрабатываем в OSGi-фреймворке и мы используем Причал . Список необходимых импортных товаров довольно длинный (я спрятал некоторые…):

import com.google.gson.Gson;
import it.hiddenstuff.common.topic.TopicConstants;
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Hashtable;

и здесь у вас есть объявление класса с правильными аннотациями и конструктором:

@WebSocket
public class SellWebSocket implements EventHandler {

    public SellWebSocket() {
        BundleContext bundleContext = FrameworkUtil.
            getBundle(SellWebSocket.class).getBundleContext();
        Hashtable stringStringHashMap = new Hashtable<>();
        stringStringHashMap.
            put( EventConstants.EVENT_TOPIC , TopicConstants.TOPIC_END_SELL);
        bundleContext.
            registerService(EventHandler.class , this ,  stringStringHashMap);
    }
}

Затем вам нужно добавить некоторые объявления для управления сеансом, журналами и конечными точками:

    private Session session;
    private RemoteEndpoint remote;
    private Logger log = LoggerFactory.getLogger(getClass());

    public Session getSession() {
        return session;
    }

    public void setSession(Session session) {
        this.session = session;
    }

    public RemoteEndpoint getRemote() {
        return remote;
    }

Что касается внешнего интерфейса, вам нужно слушать события ( открывать , закрывать , отправить , получить ):

    @OnWebSocketConnect
    public void onConnect(Session session) {
        setSession(session);
        this.remote = session.getRemote();
    }

    @OnWebSocketClose
    public void onClose(int statusCode, String reason) {
        this.session = null;
    }

    @OnWebSocketMessage
    public void onText(String message) {
        if (session == null) {
            log.debug("null session");
            // no connection, do nothing.
            // this is possible due to async behavior
            return;
        }
        //do something
    }

    /**
     * Called by the {@link EventAdmin} service to notify the listener of an
     * event.
     *
     * @param event The event that occurred.
     */
    @Override
    public void handleEvent(Event event) {
        //do what you need to do
    }

Выводы

До этого я был не совсем знаком со всеми этими вещами, и поиск в Google немного свел меня с ума, так как было трудно найти решение со всеми нужными характеристиками: иногда вы находите socket.io , иногда вы находите старые классы React, когда вам нужны крючки, и некоторые подобные проблемы. Во всяком случае, мне удалось собрать все вместе, выйдя с этим решением. Поскольку я не претендую на роль эксперта, не стесняйтесь комментировать и добавлять полезные предложения. Если вместо этого вы считаете, что эта статья полезна, я был бы очень рад узнать 😀

Оригинал: “https://dev.to/fpeluso/a-simple-websocket-between-java-and-react-5c98”