Angenommen, wir möchten eine Client-Server-Anwendung implementieren, in der die erforderlichen Daten auf der Clientseite generiert werden. Auf der Serverseite wird die Berechnung durchgeführt und als Ergebnis an den Client zurückgegeben. Berücksichtigen wir einen einfachen Taschenrechner (machen wir es noch einfacher, 4 Operatoren, Operanden ohne Brüche und arbeiten nach dem Schema [operand1] [operator] [operand2] [result]) und implementieren wir ihn beispielsweise in einer Art Programmiersprache (Programmiersprache) ), zum Beispiel Java, mit dem Anwendungsserver (zum Beispiel WildFly / JBoss) + Client (Sie können JavaFX verwenden), können Sie dies auf folgende Weise tun:
Dieselbe Option kann mithilfe von RMI (Remote Method Invocation) ohne Server, GUI-Client und EJB in der Konsole gelöst werden. Wir werden diese Option jedoch nicht in Betracht ziehen, sondern mit einer interessanteren Implementierung fortfahren.1. Wir benötigen folgende Zutaten:
1.1. JDK,
1.2. IDE (mit Java EE-Unterstützung),
1.3. WildFly (oder ein anderer Java-Anwendungsserver),
1.4. SceneBuilder (zur bequemen und schnellen Erstellung der Benutzeroberfläche).
Um den Client mit dem Server zu verbinden, verwenden wir JNDI (einen Namens- und Verzeichnisdienst) mit EJB (ein Framework zum Erstellen von Geschäftslogik).
2. Erstellen Sie eine Implementierung der Serverseite:
2.1. Die Remote-Schnittstelle, über die die Kommunikation zwischen Clients und Server erfolgt (verwenden Sie die
Remote- Anmerkung - die EJB-Komponente verwendet RMI).
package com.calc.server; import javax.ejb.Remote; @Remote public interface CalcRemote { int add(int a, int b); int sub(int a, int b); int mul(int a, int b); int div(int a, int b) throws MyException; }
2.2. Eine Klasse, die diese Schnittstelle implementiert (wir verwenden die Annotation @Stateless - eine zustandslose Sitzungskomponente).
package com.calc.server; import javax.ejb.Stateless; @Stateless(name = "CalcSessionEJB") public class CalcSessionBean implements CalcRemote { public CalcSessionBean() { } @Override public int add(int a, int b) { return a + b; } @Override public int sub(int a, int b) { return a - b; } @Override public int mul(int a, int b) { return a * b; } @Override public int div(int a, int b) throws MyException { try { return a / b; } catch (ArithmeticException ex) { throw new MyException("Divide by Zero!!!"); } } }
2.3. Fügen Sie unsere Ausnahmeklasse hinzu, die eine Division durch Null oder das falsche Format signalisiert.
package com.calc.server; public class MyException extends Exception { public MyException(String message) { super(message); } }
2.4. Mit der IDE erstellen wir eine EAR-Datei (Enterprise Archive), starten den Server (es ist mit einem Standard-Port möglich), stellen ihn bereit und wenn keine Fehler festgestellt wurden, ist der Serverteil fertig.
Das Serverprotokoll kann folgendermaßen aussehen:
java:global/Calc_ear_exploded/ejb/CalcSessionEJB!com.calc.server.CalcRemote java:app/ejb/CalcSessionEJB!com.calc.server.CalcRemote java:module/CalcSessionEJB!com.calc.server.CalcRemote java:jboss/exported/Calc_ear_exploded/ejb/CalcSessionEJB!com.calc.server.CalcRemote ejb:Calc_ear_exploded/ejb/CalcSessionEJB!com.calc.server.CalcRemote java:global/Calc_ear_exploded/ejb/CalcSessionEJB java:app/ejb/CalcSessionEJB java:module/CalcSessionEJB
3. Wir erstellen die Implementierung des Client-Teils:
3.1. Skizzieren Sie in SceneBuilder das folgende Taschenrechner-Layout (main.fxml). Wir werden CSS vorerst nicht umbrechen:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="321.0" prefWidth="231.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="com.calc.client.impl2.controller.Controller"> <children> <Label disable="false" layoutX="24.0" layoutY="15.0" prefHeight="28.0" prefWidth="189.0" text="EJB Calculator" /> <TextField fx:id="displayTextField" layoutX="24.0" layoutY="43.0" prefHeight="56.0" prefWidth="182.0" /> <Button fx:id="num7Button" layoutX="24.0" layoutY="110.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="7" /> <Button fx:id="num8Button" layoutX="72.0" layoutY="110.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="8" /> <Button fx:id="num9Button" layoutX="119.0" layoutY="110.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="9" /> <Button fx:id="divButton" layoutX="166.0" layoutY="110.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="/" /> <Button fx:id="num4Button" layoutX="24.0" layoutY="161.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="4" /> <Button fx:id="num5Button" layoutX="72.0" layoutY="161.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="5" /> <Button fx:id="num6Button" layoutX="119.0" layoutY="161.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="6" /> <Button fx:id="mulButton" layoutX="166.0" layoutY="161.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="*" /> <Button fx:id="num1Button" layoutX="24.0" layoutY="209.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="1" /> <Button fx:id="num2Button" layoutX="72.0" layoutY="209.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="2" /> <Button fx:id="num3Button" layoutX="119.0" layoutY="209.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="3" /> <Button fx:id="subButton" layoutX="166.0" layoutY="209.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="-" /> <Button fx:id="num0Button" layoutX="24.0" layoutY="259.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="0" /> <Button fx:id="clrButton" layoutX="72.0" layoutY="259.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="C" /> <Button fx:id="resButton" layoutX="119.0" layoutY="259.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="=" /> <Button fx:id="addButton" layoutX="166.0" layoutY="259.0" mnemonicParsing="false" prefHeight="39.0" prefWidth="40.0" text="+" /> </children> </AnchorPane>
3.2. Wir verbinden den Klassencontroller mit dem fxml-Formular, um die GUI (Sticky Form) zu entsperren, während auf Daten vom Server gewartet wird. Fügen Sie der Schaltfläche "=" einen neuen Thread hinzu:
Code-Ansicht package com.calc.client.impl2.controller; import com.calc.server.CalcRemote; import com.calc.server.MyException; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.TextField; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import java.util.Properties; public class Controller implements Runnable { private Calculator calculator; @FXML private TextField displayTextField; @FXML private Button num1Button; @FXML private Button num2Button; @FXML private Button num3Button; @FXML private Button num4Button; @FXML private Button num5Button; @FXML private Button num6Button; @FXML private Button num7Button; @FXML private Button num8Button; @FXML private Button num9Button; @FXML private Button num0Button; @FXML private Button addButton; @FXML private Button subButton; @FXML private Button mulButton; @FXML private Button divButton; @FXML private Button clrButton; @FXML private Button resButton; @FXML private void initialize() { System.out.println("initialize()"); calculator = new Calculator(); displayTextField.setText("0"); num1Button.setOnAction(event -> displayTextField.setText(calculator.addNumber("1"))); num2Button.setOnAction(event -> displayTextField.setText(calculator.addNumber("2"))); num3Button.setOnAction(event -> displayTextField.setText(calculator.addNumber("3"))); num4Button.setOnAction(event -> displayTextField.setText(calculator.addNumber("4"))); num5Button.setOnAction(event -> displayTextField.setText(calculator.addNumber("5"))); num6Button.setOnAction(event -> displayTextField.setText(calculator.addNumber("6"))); num7Button.setOnAction(event -> displayTextField.setText(calculator.addNumber("7"))); num8Button.setOnAction(event -> displayTextField.setText(calculator.addNumber("8"))); num9Button.setOnAction(event -> displayTextField.setText(calculator.addNumber("9"))); num0Button.setOnAction(event -> displayTextField.setText(calculator.addNumber("0"))); addButton.setOnAction(event -> { calculator.addOperator("+"); displayTextField.setText(""); }); subButton.setOnAction(event -> { calculator.addOperator("-"); displayTextField.setText(""); }); mulButton.setOnAction(event -> { calculator.addOperator("*"); displayTextField.setText(""); }); divButton.setOnAction(event -> { calculator.addOperator("/"); displayTextField.setText(""); }); resButton.setOnAction(event -> new Thread(this).start()); clrButton.setOnAction(event -> displayTextField.setText("")); } private void doRequest(String[] data) throws NamingException, MyException { Properties props = new Properties(); props.put(Context.INITIAL_CONTEXT_FACTORY, "org.wildfly.naming.client.WildFlyInitialContextFactory");
3.3. Füge die Logik des einfachsten Rechners hinzu:
package com.calc.client.impl2.controller; import com.calc.server.MyException; public class Calculator { private String buffer = "", operator, operand1, operand2; private boolean isOperator = false; public String addNumber(String value) { buffer += value; if (!isOperator) { operand1 = buffer; } else { operand2 = buffer; } return buffer; } public void addOperator(String value) { operator = value; buffer = ""; isOperator = true; } public String[] getResult() throws MyException { isOperator = false; buffer = ""; int check; try { check = Integer.parseInt(operand1); check = Integer.parseInt(operand2); } catch (NumberFormatException ex) { throw new MyException("Wrong format!!!"); } return new String[]{operand1, operand2, operator}; } }
3.5. Fügen Sie die Client-Bibliothek hinzu (im Fall von WildFly ist dies jboss-client.jar), und führen Sie die GUI aus.
Wie aus den angehängten Codes hervorgeht, gibt der Benutzer Ziffern in den Puffer für Operanden ein und wählt den Operator aus. Wenn die Taste "=" gedrückt wird, wird eine Verbindung zum Server hergestellt (über den JNDI-Dienst). Die Aufschrift in der Anzeige "WAITING ..." zeigt an, dass der Server auf eine Antwort wartet.
Wir stellen auch einige Ausnahmen fest: NumberFormatException (abgefangen, wenn der Benutzer Daten auf dem Client eingibt) und ArithmeticException (abgefangen, wenn auf dem Server durch Null dividiert).