[英]How to return objects from inputStream Client to a Javafx Controller?
所以基本上我有一個 MainController class ,每個按鈕都有方法。 我還有一個服務器多客戶端應用程序。 在客戶端中,我有一個方法 sendMessage,它發送一個字符串和一個 Object 作為 outputStreams 到服務器的參數。
在相同的方法中,我有 2 個用於來自服務器的消息的 inputStream 和一個 object。 問題是這個方法在實現 run 方法的線程上運行,我無法返回 object。
I tried to create a static class that saves these, but the getters are null, when called in Controller class.
實現這一目標的最佳方法是什么?
public void onSaveButton(javafx.event.ActionEvent actionEvent) throws Exception {
Parent root = null;
Boolean type = false;
String message = null;
if (adminCheckbox.isSelected()) {
root = FXMLLoader.load(getClass().getResource("/fxml/admin.fxml"));
type = true;
message = "Admin";
}
if (competitorCheckbox.isSelected()) {
root = FXMLLoader.load(getClass().getResource("/fxml/competitor.fxml"));
message = "Competitor";
}
PersonEntity personEntity = new PersonEntity();
personEntity.setIdTeam(Integer.parseInt(teamField.getText()));
personEntity.setType(type);
personEntity.setUsername(usernameField.getText());
client.sendMessageToServer(message, personEntity);
System.out.println(Utils.getMessage());}
和客戶端方法:
public void sendMessageToServer(String message, Object object) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Say something and the message will be sent to the server: ");
//For receiving and sending data
boolean isClose = false;
while (!isClose) {
try {
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
if (message.equals("Bye")) {
isClose = true;
}
outputStream.writeObject(message);
outputStream.writeObject(object);
String messageFromServer = (String) inputStream.readObject();
//System.out.println(messageFromServer);
int index = messageFromServer.indexOf(' ');
String word = messageFromServer.substring(0, index);
if (messageFromServer.equals("Bye")) {
isClose = true;
}
if (!word.equals("LIST")) {
Object obj = (Object) inputStream.readObject();
Utils.setMessage(messageFromServer);
return;
//Utils.setObject(obj);
//System.out.println("IN FOR " + Utils.getMessage());
} else {
List<Object> list = (List<Object>) inputStream.readObject();
Utils.setMessage(messageFromServer);
Utils.setObjects(list);
return;
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
您可以使用線程安全的 ConcurrentLinkedQueue(當然是靜態的)。 Utils.setObjects
會將每個元素添加到隊列中。 在客戶端,您偶爾會輪詢隊列中要在 UI 中顯示的新項目。
參考文檔: https://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html
我不知道您的服務器是什么,也不知道您的應用程序的 rest 是什么。 我知道您正在使用原始 TCP sockets 使用自定義協議進行通信。
我所做的是從 Java 教程中獲取類似示例的代碼。 該代碼是 KnockKnock 客戶端服務器代碼,來自: Writing the Server Side of a Socket 。 基本的服務器代碼沒有改變,我只是用 JavaFX UI 替換了基於控制台的客戶端。
未更改的服務器代碼:
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KKMultiServer.java
https://docs.oracle.com/javase/tutorial/networking/sockets/examples/KKMultiServerThread.java
替換控制台客戶端:
我提供了兩種不同的客戶端實現; 一個在 JavaFX 應用程序線程上進行同步客戶端調用,另一個使用 JavaFX 任務進行異步客戶端調用。
當前基於異步任務的解決方案對於完整的生產系統來說不夠健壯,因為它在技術上可能會丟失消息並且它不能健壯地匹配請求和響應消息。 但是對於這樣的演示,它是可以的。
為了簡單的執行,UI 應用程序在運行時都會在預定義的端口上啟動本地服務器,但您可以刪除從 UI 應用程序啟動服務器的代碼,並根據需要從命令行運行服務器。
KnockKnockSyncClient.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class KnockKnockSyncClient {
private Socket socket;
private PrintWriter out;
private BufferedReader in;
public String connect(String host, int port) {
try {
socket = new Socket(host, port);
out = new PrintWriter(
socket.getOutputStream(),
true
);
in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()
)
);
return in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String sendMessage(String request) {
String response = null;
try {
out.println(request);
response = in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
public void disconnect() {
try {
if (socket != null) {
socket.close();
socket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
KnockKnockSyncApp
import javafx.animation.FadeTransition;
import javafx.application.*;
import javafx.geometry.Insets;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class KnockKnockSyncApp extends Application {
private static final String HOST = "localhost";
private static final int PORT = 8809;
public static final String QUIT_RESPONSE = "Bye.";
private ExecutorService serverExecutor;
private KnockKnockSyncClient client;
private static final String CSS = """
data:text/css,
.root {
-fx-font-size: 20;
}
.list-cell {
-fx-alignment: baseline-right;
-fx-text-fill: purple;
}
.list-cell:odd {
-fx-alignment: baseline-left;
-fx-text-fill: darkgreen;
}
""";
@Override
public void init() {
serverExecutor = Executors.newSingleThreadExecutor(r -> new Thread(r, "KKServer"));
serverExecutor.submit(
() -> {
try {
KKMultiServer.main(new String[]{ PORT + "" });
} catch (Exception e) {
e.printStackTrace();
}
}
);
client = new KnockKnockSyncClient();
}
@Override
public void start(Stage stage) {
ListView<String> messageView = new ListView<>();
TextField inputField = new TextField();
inputField.setPromptText("Enter a message for the server.");
inputField.setOnAction(event -> {
String request = inputField.getText();
messageView.getItems().add(request);
String response = client.sendMessage(request);
messageView.getItems().add(response);
messageView.scrollTo(Math.max(0, messageView.getItems().size() - 1));
inputField.clear();
if (QUIT_RESPONSE.equals(response)) {
closeApp(inputField.getScene());
}
});
VBox layout = new VBox(10,
messageView,
inputField
);
layout.setPadding(new Insets(10));
layout.setPrefWidth(600);
Scene scene = new Scene(layout);
scene.getStylesheets().add(CSS);
stage.setScene(scene);
stage.show();
inputField.requestFocus();
String connectResponse = client.connect(HOST, PORT);
if (connectResponse != null) {
messageView.getItems().add(connectResponse);
}
}
private void closeApp(Scene scene) {
Parent root = scene.getRoot();
root.setDisable(true);
FadeTransition fade = new FadeTransition(Duration.seconds(1), root);
fade.setToValue(0);
fade.setOnFinished(e -> Platform.exit());
fade.play();
}
@Override
public void stop() {
client.disconnect();
serverExecutor.shutdown();
}
public static void main(String[] args) {
launch();
}
}
KnockKnockAsyncClient.java
import javafx.concurrent.Task;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
public class KnockKnockAsyncClient extends Task<Void> {
private final String host;
private final int port;
private final BlockingQueue<String> messageQueue = new LinkedBlockingDeque<>();
public KnockKnockAsyncClient(String host, int port) {
this.host = host;
this.port = port;
}
@Override
protected Void call() {
try (
Socket kkSocket = new Socket(host, port);
PrintWriter out = new PrintWriter(kkSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(kkSocket.getInputStream()));
) {
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null) {
// this is not a completely robust implementation because updateMessage
// can coalesce responses and there is no matching in send message calls
// to responses. A more robust implementation may allow matching of
// requests and responses, perhaps via a message id. It could also
// replace the updateMessage call with storage of results in a collection
// (e.g. an observable list) with thread safe notifications of response
// arrivals, e.g. through CompleteableFutures and/or Platform.runLater calls.
updateMessage(fromServer);
System.out.println("Server: " + fromServer);
if (fromServer.equals("Bye."))
break;
fromUser = messageQueue.take();
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
} catch (InterruptedException e) {
if (isCancelled()) {
updateMessage("Cancelled");
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void sendMessage(String request) {
messageQueue.add(request);
}
}
KnockKnockAsyncApp.java
import javafx.animation.FadeTransition;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class KnockKnockAsyncApp extends Application {
private static final String HOST = "localhost";
private static final int PORT = 8809;
public static final String QUIT_RESPONSE = "Bye.";
private ExecutorService serverExecutor;
private ExecutorService clientExecutor;
private static final String CSS = """
data:text/css,
.root {
-fx-font-size: 20;
}
.list-cell {
-fx-alignment: baseline-right;
-fx-text-fill: purple;
}
.list-cell:odd {
-fx-alignment: baseline-left;
-fx-text-fill: darkgreen;
}
""";
@Override
public void init() {
serverExecutor = Executors.newSingleThreadExecutor(r -> new Thread(r, "KKServer"));
serverExecutor.submit(
() -> {
try {
KKMultiServer.main(new String[]{ PORT + "" });
} catch (Exception e) {
e.printStackTrace();
}
}
);
clientExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
final AtomicInteger threadNum = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r,"KKClient-" + threadNum.getAndAdd(1));
}
});
}
@Override
public void start(Stage stage) {
ListView<String> messageView = new ListView<>();
KnockKnockAsyncClient client = new KnockKnockAsyncClient(HOST, PORT);
// monitor and action responses from the server.
client.messageProperty().addListener((observable, oldValue, response) -> {
if (response != null) {
logMessage(messageView, response);
}
if (QUIT_RESPONSE.equals(response)) {
closeApp(messageView.getScene());
}
});
TextField inputField = new TextField();
inputField.setPromptText("Enter a message for the server.");
inputField.setOnAction(event -> {
String request = inputField.getText();
logMessage(messageView, request);
client.sendMessage(request);
inputField.clear();
});
VBox layout = new VBox(10,
messageView,
inputField
);
layout.setPadding(new Insets(10));
layout.setPrefWidth(600);
Scene scene = new Scene(layout);
scene.getStylesheets().add(CSS);
stage.setScene(scene);
stage.show();
inputField.requestFocus();
clientExecutor.submit(client);
}
private void logMessage(ListView<String> messageView, String request) {
messageView.getItems().add(request);
messageView.scrollTo(Math.max(0, messageView.getItems().size() - 1));
}
private void closeApp(Scene scene) {
Parent root = scene.getRoot();
root.setDisable(true);
FadeTransition fade = new FadeTransition(Duration.seconds(1), root);
fade.setToValue(0);
fade.setOnFinished(e -> Platform.exit());
fade.play();
}
@Override
public void stop() {
clientExecutor.shutdown();
serverExecutor.shutdown();
}
public static void main(String[] args) {
launch();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.