NOVINKA! E-learningové kurzy umělé inteligence. Nyní AI za nejlepší ceny. Zjisti více:
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Lekce 19 - Java chat - Klient - Spojení se serverem 3. část

V minulé lekci, Java chat - Klient - Spojení se serverem 2. část, jsme se věnovali implementaci klientského komunikátoru.

V dnešním Java tutoriálu konečně vytvoříme stabilní spojení se serverem.

Upravení připojovacího kontroleru

Začneme upravením třídy ConnectController. Ve třídě vytvoříme novou instanční proměnnou typu IClientCommunicationService. Rovnou této proměnné vytvoříme setter, abychom mohli komunikátor nastavit:

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 nastavovat, protože nemáme v projektu implementovanou žádnou správu závislostí, jako tomu bylo u serveru. Dále v setteru vytváříme BooleanProperty connected, na kterou bindujeme disableProperty tlačítek pro připojení a odpojení. disableProperty tlačítka "připojit" má trošku složitější logiku, protože se musíme ještě dívat, zda-li se máme k čemu připojit (je vyplněn TextField se serverem).

Dále upravíme metodu initialize(), do které přidáme reakci na výběr 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()));
});

Voláním metod getSelectionModel().selectedItemProperty() získáme pozorovatelnou read-only property, na kterou přidáme listener, který se zavolá vždy, když změníme výběr položky v listView. Pokud bude nová hodnota null, tak nic dělat nebudeme, v opačném případě vyplníme TextField txtServer hodnotou ve formátu: "server:port".

Nyní vytvoříme nejdůležitější metodu v kontroleru, connect(), pomocí které se budeme připojovat 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 první části metody parsujeme z TextFieldu adresu serveru a port, na kterém server naslouchá. Pokud se nepodaří naparsovat port serveru, zobrazíme upozornění uživateli, že port není ve validním stavu. Následuje zavolání metody connect() nad instancí našeho komunikátoru. Metodou exceptionaly() ošetříme případ, kdy se spojení nepodařilo navázat. Když se jednou dostaneme do větve exceptionaly(), můžeme v ní zůstat tak, že opět vyhodíme nějakou výjimku, nebo vrátíme smysluplnou hodnotu, čímž se dostaneme do výchozí větve. Větev thenAccept() je zavolána v případě, že spojení se úspěšně vytvořilo.

Nakonec nám už jenom zbývá nastavit odpovídajícím tlačítkům správnou akci:

@FXML
private void handleConnect(ActionEvent actionEvent) {
    connect();
}

@FXML
private void handleDisconnect(ActionEvent actionEvent) {
    communicator.disconnect();
}

Upravení hlavního kontroleru

Nyní se přesuneme do hlavního kontroleru, ve kterém budeme držet jedinou instanci komunikátoru. Vytvoříme tedy ve třídě MainController instanční konstantu komunikátoru:

private final IClientCommunicationService communicator = new ClientCommunicationService();

Dále upravíme metodu handleConnect(), ve které voláme zobrazení 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();
    }
}

Metoda showNewWindow() vrací kontroler nového okna. Tento kontroler si uložíme do lokální proměnné a metodou setCommunicator() nastavíme kontroleru komunikátor.

Ještě využijeme metodu onClose(), která se zavolá při zavření okna. V této metodě se pro jistotu odpojíme od serveru. Tím bezpečně ukončíme spojení a veškerá vlákna s ním spojená:

@Override
public void onClose() {
    communicator.disconnect()
}

Testování funkčnosti

Konečně se můžeme připojit k serveru. Z předchozí lekce máme funkční vyhledávání lokálních serverů, tak toho hned využijeme. Spustíme server a klienta. Dále zobrazíme okno pro připojení. Když se zobrazí v seznamu náš spuštěný server, klikneme na tuto položku. V té chvíli by se měl vyplnit TextField s adresou serveru a portem a tlačítko na připojení by mělo být aktivní. Po kliknutí na tlačítko by se měl zobrazit dialog, že připojení proběhlo úspěšně a tlačítko pro připojení by opět nemělo být aktivní. Naopak tlačítko pro připojení by se mělo aktivovat. Že jste se opravdu připojili poznáte nejlépe tak, že se změní u připojeného serveru počet připojených uživatelů:

Úspěšné připojení k serveru - Server pro klientské aplikace v Javě

To by bylo pro dnešní lekci vše.

V následujícím kvízu, Kvíz - Spojení klienta se serverem v Javě, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 15x (121.04 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Java chat - Klient - Spojení se serverem 2. část
Všechny články v sekci
Server pro klientské aplikace v Javě
Přeskočit článek
(nedoporučujeme)
Kvíz - Spojení klienta se serverem v Javě
Článek pro vás napsal Petr Štechmüller
Avatar
Uživatelské hodnocení:
Ještě nikdo nehodnotil, buď první!
Autor se věnuje primárně programování v Javě, ale nebojí se ani webových technologií.
Aktivity