【问题标题】:Java as external component using Swing: main thread never exits使用 Swing 作为外部组件的 Java:主线程永远不会退出
【发布时间】:2013-07-17 10:39:35
【问题描述】:

我正在尝试在另一个程序中使用 Java 组件。该程序是运行在 Tomcat 上的 Web 应用程序,我的组件使用 Swing 打开 Web 浏览器。提示用户导航到特定页面,并使用 JFrame 上的控件,页面以 HTML 格式保存在本地。这个本地保存的文件稍后将用于进一步阐述。 问题是,当从 Eclipse 执行时,我的代码可以正常工作。但是,当我使用在 Tomcat 上运行的应用程序中的组件时,它运行不正确。出现该窗口,导航正在工作,并且可以毫无问题地检索数据。问题是主应用程序(在 Tomcat 上运行的应用程序)必须在组件(Java)完成工作后恢复执行。显然,出现了问题,因为 Web 应用程序只是挂起,并且永远不会继续。

在我的组件中,我使用了两个类:Browser 和 Helper。浏览器基于 DJ NativeSwing 库,包含初始化和显示简单 Web 浏览器的逻辑。 Helper 类为我提供了一个“前端”方法,它允许我在自己的线程中执行浏览器。我使用的是 SwingUtilities.invokeAndWait 而不是 invokeLater,因为我不太清楚如何使用 wait() 和 notify()。我试过了,失败了。

总结一下代码,它看起来像这样:

import javax.swing.SwingUtilities;
import chrriis.dj.nativeswing.swtimpl.NativeInterface;

public class Helper {
    public String Browse() {
    Browser vb = new Browser();
    try {
        Browser.log("This is Helper, now initiating.");
        NativeInterface.open();
        Thread th = new Thread(vb);
        Browser.log("Helper is invoking thread...");
        SwingUtilities.invokeAndWait(th);
        NativeInterface.runEventPump();
        Browser.log("Thread exited! Back to Helper!");
        System.out.println(vb.getData());
        Browser.log("Returning data to caller: \n" + vb.getData());
        return vb.getData();
    }catch (Exception ex) {
        ex.printStackTrace();
        Browser.log("MainFail: " + ex.getMessage());
        return ex.getMessage();
    }
}

还有浏览器类:

import java.awt.BorderLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import chrriis.dj.nativeswing.NativeSwing;
import chrriis.dj.nativeswing.swtimpl.NativeInterface;
import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser;

public class Browser extends JFrame implements ActionListener, Runnable {

    private static final long serialVersionUID = 1L;
    private JButton btn;
    private JWebBrowser webBrowser;
    private JPanel panel;
    private String data = "";

    public static void log(String s) {
        try {
            BufferedWriter ostr = new BufferedWriter(new FileWriter("F:/java_out.log", true));
            Date dt = new Date();
            SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss");
            String str = formatter.format(dt) + "\t -> " + s + "\n";
            ostr.write(str);
            ostr.close();
        } catch(Exception ex) {
            System.out.println("Logger: " + ex.getMessage());
        }
    }

    public Browser() {
        Browser.log("Initializing...");
        NativeSwing.initialize();
        NativeInterface.open();

        panel = new JPanel();
        btn = new JButton();
        btn.setText("Save Page");
        btn.addActionListener(this);
        btn.setMargin(new Insets(5, 5, 5, 5));
        VisureBrowser.log("Button is ready!");

        JPanel webBrowserPanel = new JPanel(new BorderLayout());
        webBrowserPanel.setBorder(BorderFactory.createTitledBorder("Navigate and save"));
        webBrowser = new JWebBrowser();
        webBrowser.setButtonBarVisible(true);
        webBrowser.setMenuBarVisible(false);
        webBrowser.setLocationBarVisible(true);
        VisureBrowser.log("Panel is ready!");

        this.setTitle("Simple Browser");
        this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        this.setSize(800, 600);
        this.setLayout(new BorderLayout());
        this.setLocationByPlatform(true);
        this.setLocationRelativeTo(null);
        VisureBrowser.log("Frame is ready!");

        this.add(btn, BorderLayout.BEFORE_FIRST_LINE);
        btn.setVisible(true);
        webBrowserPanel.add(webBrowser, BorderLayout.CENTER);
        webBrowser.setVisible(true);
        this.add(webBrowserPanel, BorderLayout.CENTER);
        panel.setVisible(true);
        this.setVisible(true);

        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
            SwingUtilities.updateComponentTreeUI(this);
        } catch (Exception e) {
            Browser.log("Constructor: " + e.getMessage());
            Browser.log(e.getStackTrace().toString());
            e.printStackTrace();
        }

        Browser.log("Look and Feel ready as well! Off to work...");
    }


    public String getData() {
        return this.data;
    }


    public void close() {
        WindowEvent wev = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
        Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
    }


    public void run() {
        Browser.log("Navigating to the index page...");
        webBrowser.navigate("http://www.google.com/");
        Browser.log("Navigation successful!");
    }


    @Override
    public void actionPerformed(ActionEvent e) {
        Browser.log("An action has been performed!");
        Object src = e.getSource();
        if (src.equals(btn)) {
            try {
                Browser.log("Getting data...");
                this.data = webBrowser.getHTMLContent();
                Browser.log("Closing...");
                this.close();
            } catch( Exception ex) {
                Browser.log("ClickFail: " + ex.getMessage());
                Browser.log(ex.getStackTrace().toString());
            }
        }
    }   
}

我得到的输出是来自 Eclipse:

12:28:54     -> Initializing...
12:28:55     -> Button is ready!
12:28:55     -> Panel is ready!
12:28:55     -> Frame is ready!
12:28:56     -> Look and Feel ready as well! Off to work...
12:28:56     -> This is Helper, now initiating.
12:28:56     -> Helper is invoking thread...
12:28:56     -> Navigating to the index page...
12:28:56     -> Navigation successful!
12:29:04     -> An action has been performed!
12:29:04     -> Getting data...
12:29:04     -> Closing...
12:29:06     -> Thread exited! Back to Helper!
12:29:06     -> Returning data to caller:
.....here comes all the data.....

我在 Tomcat 中执行时得到的数据如下:

12:28:54     -> Initializing...
12:28:55     -> Button is ready!
12:28:55     -> Panel is ready!
12:28:55     -> Frame is ready!
12:28:56     -> Look and Feel ready as well! Off to work...
12:28:56     -> This is Helper, now initiating.
12:28:56     -> Helper is invoking thread...
12:28:56     -> Navigating to the index page...
12:28:56     -> Navigation successful!
12:29:04     -> An action has been performed!
12:29:04     -> Getting data...
12:29:04     -> Closing...

是的,我使用了相同的行,但输出是这样的,它只到结束行。 我没想到的是关闭窗口和恢复主要活动之间的延迟:每次运行大约 2-3 秒。我想象它与辅助(GUI)线程没有正确退出有关,但我不知道如何继续。

任何帮助将不胜感激! :)

【问题讨论】:

  • 你能解释一下你想用这个完成什么吗?为什么要从 Web 服务器启动浏览器?为什么不只提供一个 URL 供用户浏览器访问?
  • 我正在开发的网络应用程序在内部数据库中获取与特定主题相关的数据。该数据也可能来自外部来源,例如来自另一个公共服务。我想要做的是获取这些数据,从 HTML 文件中解析它。它已经完成,唯一的细节是我无法从我的应用程序访问数据。因此,我向用户展示了一个本机浏览器,该浏览器允许他导航到他想要的页面,并且我拥有所有可用的 HTML 数据。我尝试过使用 jQuery、Ajax 和诸如此类的东西:跨域请求让我被阻止了...:/
  • 另外,调用所有这些然后打印“线程退出”消息的代码是无法正确运行的代码,但我在这里找不到。你在说什么线程?
  • 您仍然没有回答问题:为什么用户不自己启动浏览器来访问您的应用程序?用户未启动浏览器,这个网页应用如何启动?
  • Tomcat webapp 不在浏览器中运行。它在服务器上运行,可能没有连接任何屏幕,并且可能远离用户的机器。当服务器上的 webapp 等待显示在服务器屏幕上的 JFrame 中的输入(如果有)时,用户将盯着它的浏览器。在您的开发机器上,服务器和客户端机器是相同的,但在生产中,这将不再是真的。因此问题。

标签: java swing tomcat


【解决方案1】:

你做错了。

Tomcat 是一个 Web 应用程序服务器,不应弹出任何 Swing 组件。如果服务器在其他地方运行,每个用户最终都会在服务器上启动 Swing 窗口,而用户将永远看不到它们。您所遇到的(Tomcat 启动了一个 Swing 窗口并能够实际看到它)只是一个巧合,因为您的服务器在 localhost 上运行。

您想要做的是让您的用户从网络浏览器开始,然后导航到正确的站点以使用您的内容。也就是说,网络浏览器应该已经可用:您不应该代表您的用户启动一个。

【讨论】:

  • 你是对的。我不知道这在实际条件下执行时会如何表现,但是我必须确保它首先在本地执行我想要的操作。这不是最佳做法,但这是我目前唯一的方法。我的问题是,虽然浏览器已经可用,但我还没有想出另一种获取用户信息的方法。
  • 您需要什么“信息”?这种尴尬的设置你是怎么理解的?
  • 我正在开发一个数据库来收集对象的财务数据。显然,这是一件相当敏感的事情,我想以最好的方式去做。我目前也在考虑其他选择,但我认为没有任何简单的方法可以获取它... :/ 我上次的调查使我相信使用代理 PHP 脚本的跨域通信可能是去。您对此有何看法? :)
  • 我认为你不知道自己在做什么。我不明白为什么应用程序服务器需要启动 Web 浏览器...如果用户需要通过 Web 浏览器访问您的服务,用户将启动浏览器并转到您的服务的 URL。如果您需要用户提供信息,请通过网络表单索取。
  • 这个想法实际上已经被放弃了,它更像是个人的“尝试和错误”的事情。我真的不知道我在做什么,我知道这听起来如何,但我想相信我会掌握它的窍门。
猜你喜欢
  • 2020-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-09
  • 1970-01-01
  • 2015-08-03
  • 1970-01-01
相关资源
最近更新 更多