19. diel - Java chat - Klient - Spojenie so serverom 3. časť
V minulej lekcii, Java chat - Klient - Spojenie so serverom 2. časť , sme sa venovali implementácii klientského komunikátora. V dnešnom Java tutoriálu konečne vytvoríme stabilné spojenie so serverom.
Upravenie pripojovacieho kontroleru
Začneme upravením triedy ConnectController
. V triede
vytvoríme novú inštančný premennú typu
IClientCommunicationService
. Rovno tejto premennej vytvoríme
setter, aby sme mohli komunikátor nastaviť:
public void setCommunicator(IClientCommunicationService communicator) { this.communicator = communicator; final BooleanBinding connected = Bindings.createBooleanBinding(() -> this.communicator.getConnectionState() == ConnectionState.CONNECTED, this.communicator.connectionStateProperty()); btnConnect.disableProperty().bind(connected.or(txtServer.textProperty().isEmpty())); btnDisconnect.disableProperty().bind(connected.not()); lblConnectedTo.textProperty().bind(this.communicator.connectedServerNameProperty()); }
Komunikátor musíme takto nastavovať, pretože nemáme v projekte
implementovanú žiadnu správu závislostí, ako tomu bolo u servera. Ďalej v
Setter vytvárame BooleanProperty
connected
,
na ktorú bindujeme disableProperty
tlačidiel pre pripojenie a
odpojenie. DisableProperty
tlačidla "pripojiť" má trošku
zložitejšie logiku, pretože sa musíme ešte pozerať, či ak sa máme na čo
pripojiť (je vyplnený TextField
so serverom).
Ďalej upravíme metódu initialize()
, do ktorej pridáme
reakciu na výber položky z listView
:
lvServers.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { if (newValue == null) { return; } txtServer.textProperty().set(String.format("%s:%d", newValue.getServerAddress().getHostAddress(), newValue.getPort())); });
Volaním metód getSelectionModel().selectedItemProperty()
získame pozorovateľnú read-only property, na ktorú pridáme listener, ktorý
sa zavolá vždy, keď zmeníme výber položky v listView
. Pokiaľ
bude nová hodnota null
, tak nič robiť nebudeme, v opačnom
prípade vyplníme TextField
txtServer
hodnotou vo
formáte: "server: port".
Teraz vytvoríme najdôležitejšie metódu v kontroleru,
connect()
, pomocou ktorej sa budeme pripájať na server:
private void connect() { final String hostPort = txtServer.textProperty().get(); final String host = hostPort.substring(0, hostPort.indexOf(":")); final String portRaw = hostPort.substring(hostPort.indexOf(":") + 1); int port; try { port = Integer.parseInt(portRaw); } catch (Exception ex) { Alert alert = new Alert(AlertType.ERROR); alert.setHeaderText("Chyba"); alert.setContentText("Port serveru se nezdařilo naparsovat."); alert.showAndWait(); return; } this.communicator.connect(host, port) .exceptionally(throwable -> { Alert alert = new Alert(AlertType.ERROR); alert.setHeaderText("Chyba"); alert.setContentText("Připojení k serveru se nezdařilo."); alert.showAndWait(); throw new RuntimeException(throwable); }) .thenAccept(ignored -> { Alert alert = new Alert(AlertType.INFORMATION); alert.setHeaderText("Informace"); alert.setContentText("Spojení bylo úspěšně navázáno."); alert.showAndWait(); }); }
V prvej časti metódy dekóduje z TextField
u adresu servera a
port, na ktorom server počúva. Ak sa nepodarí naparsovat port servera,
zobrazíme upozornenie užívateľovi, že port nie je vo validným stave.
Nasleduje zavolanie metódy connect()
nad inštancií nášho
komunikátora. Metódou exceptionaly()
ošetríme prípad, keď sa
spojenie nepodarilo nadviazať. Keď sa raz dostaneme do vetvy
exceptionaly()
, môžeme v nej zostať tak, že opäť vyhodíme
nejakú výnimku, alebo vrátime zmysluplnú hodnotu, čím sa dostaneme do
východiskovej vetvy. Vetva thenAccept()
je zavolaná v prípade,
že spojenie sa úspešne vytvorilo.
Nakoniec nám už len zostáva nastaviť zodpovedajúcim tlačidlám správnu akciu:
@FXML private void handleConnect(ActionEvent actionEvent) { connect(); } @FXML private void handleDisconnect(ActionEvent actionEvent) { communicator.disconnect(); }
Upravenie hlavného kontroleru
Teraz sa presunieme do hlavného kontroleru, v ktorom budeme držať jedinú
inštanciu komunikátora. Vytvoríme teda v triede MainController
inštančný konštantu komunikátora:
private final IClientCommunicationService communicator = new ClientCommunicationService();
Ďalej upravíme metódu handleConnect()
, v ktorej voláme
zobrazenia okna:
@FXML private void handleConnect(ActionEvent actionEvent) { try { final ConnectController controller = showNewWindow("connect/connect", "Připojit k serveru..."); controller.setCommunicator(communicator); } catch (IOException e) { e.printStackTrace(); } }
Metóda showNewWindow()
vracia kontrolér nového okna. Tento
kontrolér si uložíme do lokálnej premennej a metódou
setCommunicator()
nastavíme kontroleru komunikátor.
Ešte využijeme metódu onClose()
, ktorá sa zavolá pri
zatvorení okna. V tejto metóde sa pre istotu odpojíme od servera. Tým
bezpečne ukončíme spojenie a všetka vlákna s ním spojená:
@Override public void onClose() { communicator.disconnect() }
Testovanie funkčnosti
Konečne sa môžeme pripojiť k serveru. Z predchádzajúcej lekcie máme
funkčné vyhľadávanie lokálnych serverov, tak toho hneď využijeme.
Spustíme server a klienta. Ďalej zobrazíme okno pre pripojenie. Keď sa
zobrazí v zozname náš spustený server, klikneme na túto položku. V tej
chvíli by sa mal vyplniť TextField
s adresou servera a portom a
tlačidlo na pripojenie by malo byť aktívny. Po kliknutí na tlačidlo by sa
mal zobraziť dialóg, že pripojenie prebehlo úspešne a tlačidlo pripojenia
by opäť nemalo byť aktívny. Naopak tlačidlo pripojenia by sa malo
aktivovať. Že ste sa naozaj pripojili spoznáte najlepšie tak, že sa zmení
u pripojeného servera počet pripojených užívateľov.
To by bolo pre dnešné lekciu všetko. Nabudúce, v lekcii Java chat - Server - Správa užívateľov , vytvoríme jednoduchú správu užívateľov na strane servera a prihlásime sa na server pod prezývkou.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 15x (121.04 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java