我用Java编写客户端 - 服务器桌面应用程序。我写了一个运行的服务器(打开套接字)&等待客户端连接。客户端不直接与数据库(MySQL)通信,它们向服务器发送查询,服务器执行查询&将结果集转换为JSON&将其发回给客户。 在客户端我写了一个Listener类:
private class Listner implements Runnable {
private Thread t;
private final Socket socket;
private BufferedReader input;
Listner(Socket s) {
socket = s;
}
@Override
public void run() {
while (true) {
try {
String message;
message = input.readLine();
sharedInputFromServer = input.readLine();
System.out.println("message value in run(): " + message);
} catch (IOException e) {
}
try {
Thread.sleep(30);
} catch (InterruptedException ex) {
Logger.getLogger(ClientDashboard.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void start () {
try {
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("input value in start() :" + input);
} catch (IOException e) {
e.printStackTrace();
}
if (t == null) {
t = new Thread (this, "client");
t.start ();
}
}
}
为了在客户端GUI中使用返回的数据,我定义了一个变量
public String sharedInputFromServer;
并且为了测试我设置ActionPerformed用于更新带有返回值的标签的按钮
private void btn_sendToServerActionPerformed(java.awt.event.ActionEvent evt) {
if (null != output) {
String textToSend = "SELECT unit_id, unit_name FROM units;";
output.println(textToSend);
System.out.println("got the share: " + sharedInputFromServer);
lbl_clientStatus.setText(sharedInputFromServer);
}
当我第一次点击按钮时,sharedInputFromServer返回null,第二次再次返回null(run()中的消息取值)&当我第三次点击按钮时,它会返回所需的值。
答案 0 :(得分:1)
为什么它最初不起作用?
您正在通过客户端向服务器发送查询,然后从数据库中提取数据,然后将其发送回客户端。这永远不会立即发生,你不应该期望它瞬间发生。您需要重新连线并重新考虑如何从服务器获取信息。
这是正确的&从服务器&amp ;;接收查询结果的正确方法在客户端使用它?
没有一种正确的方式,但应遵循一些通用规则。了解服务器将异步回复您的查询 - 也就是说,它不会立即发生,当发生时,您将无法确切地知道,并且它将在不同的线程上发生。因此,您的解决方案也需要异步。
由于这似乎是一个Swing GUI,如果这是我的应用程序,我就不会有这样的行:
lbl_clientStatus.setText(sharedInputFromServer);
在用于向服务器发送查询的相同代码中,因为此代码假定立即响应,并且可能是您在线性控制台程序中使用的代码,但不是您应该在事件驱动的GUI中使用的代码必须等待服务器响应。相反,再次假设这是Swing,我将我的监听器代码放在SwingWorker<Void, String>
中,并且我将使用worker的发布/进程方法对来允许数据异步更新客户端GUI,何时它是可用。另一个选择是使用SwingWorker<Void, Void>
并通过向worker添加PropertyChangeListener并监听双方同意的属性来监听更改。这些方法的优点在于,对于两者,客户端GUI将在其状态发生变化时由工作人员通知,并且可以相应地响应,并且还将在Swing事件线程上进行所有Swing GUI更改,从而避免混乱的并发异常。请查看本教程了解详细信息:
例如,假设您的客户端GUI名为SimpleClientGui,并且说它有一个名为outputTextArea的JTextArea,以及一个允许外部类将文本附加到文本区域的公共方法:
public class SimpleClientGui extends JPanel {
// ...
private JTextArea outputTextArea = new JTextArea(25, 50);
// ...
public void appendToOutput(String text) {
outputTextArea.append(text);
}
您可以创建一个名为ServerListener的SwingWorker,它在Swing事件线程上调用上面的appendToOutput方法,如下所示:
import java.io.InputStream;
import java.util.List;
import java.util.Scanner;
import javax.swing.SwingWorker;
public class ServerListener extends SwingWorker<Void, String> {
private SimpleClientGui simpleClient;
private Scanner scanner;
public ServerListener(SimpleClientGui simpleClient, InputStream inputStream) {
this.simpleClient = simpleClient;
this.scanner = new Scanner(inputStream);
}
@Override
protected Void doInBackground() throws Exception {
while (scanner.hasNextLine()) {
// push the next line to the process method
publish(scanner.nextLine());
}
if (scanner != null) {
scanner.close();
}
return null;
}
@Override
protected void process(List<String> chunks) {
for (String chunk : chunks) {
// this is called on the Swing event thread
simpleClient.appendToOutput(chunk + "\n");
}
}
}